您的位置:首页 > 大数据 > 人工智能

2016 Multi-University Training Contest 1 1007 Rigid Frameworks

2016-07-20 15:30 495 查看
题目链接:点击打开链接

题目大意:有一个n*m的网格图,加几条斜边可以使它固定。

解题思路;看到这题真是一脸蒙圈啊,比赛后看了不少东西才勉强明白,对于一个网格图来说要使它固定要求是n行和m列联动。



当你在(i,j)上加入一条对角线时,第i行和第j列联动;当你同时在(i,j)和(i,k)加入对角线的时候,第i行、第j列、第k列联动;

那么问题就可以简化成两堆点,左边是n个点表示n行,右边是m个点表示m列,每作一条边表示第i行和第j列联动,只要使这个二分图完全联通就表示n行m列联动。



也就是上面这种情况,但是同时也存在下面这种情况。



这种情况明显是不联通的,所以到去掉。

对于总情况dp
[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
[m][i] * pow2[i]) % mod;
printf("%lld\n", ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息