2016 Multi-University Training Contest 1 1007 Rigid Frameworks

題目鏈接:點擊打開鏈接

題目大意:有一個n*m的網格圖,加幾條斜邊可以使它固定。

解題思路;看到這題真是一臉蒙圈啊,比賽後看了不少東西才勉強明白,對於一個網格圖來說要使它固定要求是n行和m列聯動。

當你在(i,j)上加入一條對角線時,第i行和第j列聯動;當你同時在(i,j)和(i,k)加入對角線的時候,第i行、第j列、第k列聯動;

那麼問題就可以簡化成兩堆點,左邊是n個點表示n行,右邊是m個點表示m列,每作一條邊表示第i行和第j列聯動,只要使這個二分圖完全聯通就表示n行m列聯動。

也就是上面這種情況,但是同時也存在下面這種情況。

這種情況明顯是不聯通的,所以到去掉。

對於總情況dp[n][m][k](n行,m列,k個格子有對角線)=c[n*m][k](組合數,在n*m中選k個格子)

但是對於ii行(ii<=i)jj列(jj<=j)聯通但是其他情況不聯通的情況,我們要去掉,那就是很明顯的遞推問題了。

簡單想就是dp[i][j][k]=c[n*m][k]-sigma(c[i][ii]*c[j][jj]*dp[ii][jj][kk]*c[(i-ii)*(j-jj)][k-kk])(ii<=i&&jj<=j&&kk<=k)

真的有這麼簡單嗎;

對於ii來說如果沒有用到第i行,那麼本質上和i-1時的ii有什麼區別(c[i][ii]=c[i-1][ii-1]+c[i-1][ii])

所以真正的公式應該是dp[i][j][k]=c[n*m][k]-sigma(c[i-1][ii-1]*c[j][jj]*dp[ii][jj][kk]*c[(i-ii)*(j-jj)][k-kk])(0<ii<=i&&jj<=j&&kk<=k)

當然dp[i][j][k]=c[n*m][k]-sigma(c[i][ii]*c[j-1][jj-1]*dp[ii][jj][kk]*c[(i-ii)*(j-jj)][k-kk])(ii<=i&&0<jj<=j&&kk<=k)也是可以的,但是因爲ii的循環再jj外面,所以優化ii可以縮短時間,親測優化了一倍。

代碼:

#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
#include<ctime>
#include "cstdio"
#include "string"
#include "string.h"
#include "map"
using namespace std;
#define LL long long
const int mod = 1e9 + 7;
LL dp[15][15][105];
LL c[105][105];
int pow2[111];
int n, m;
int main()
{
	c[0][0] = pow2[0] = 1;
	for (int i = 1;i <= 100;i++)
	{
		pow2[i] = (pow2[i - 1] * 2) % mod;
		c[i][0] = c[i][i] = 1;
		for (int j = 1;j < i;j++)
			c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;
	}
	dp[0][1][0] = dp[1][0][0] = 1;
	for (int i = 1;i <= 10;i++)
	{
		for (int j = 1;j <= 10;j++)
		{
			if (i == 1 || j == 1)
			{
				dp[i][j][i + j - 1] = 1;
				continue;
			}
			for (int k = 1;k <= i*j;k++)
			{
				dp[i][j][k] = c[i*j][k];
				for (int ii = 1;ii <= i;ii++)
				{
					for (int jj = 0;jj <= j;jj++)
					{
						if (i + j == ii + jj)
							continue;
						for (int kk = 0;kk <= k;kk++)
						{
							LL temp = c[i - 1][ii - 1] * c[j][jj] % mod;
							temp = temp*dp[ii][jj][kk] % mod;
							temp = temp*c[(i - ii)*(j - jj)][k - kk];
							dp[i][j][k] = (dp[i][j][k] + mod - temp) % mod;
						}
					}
				}
			}
		}
	}
	while (scanf("%d %d", &n, &m) != EOF)
	{
		LL ans = 0;
		for (int i = 0;i <= n*m;i++)
			ans = (ans + dp[n][m][i] * pow2[i]) % mod;
		printf("%lld\n", ans);
	}
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章