您的位置:首页 > 运维架构

TopCoder SRM 548 1000分 dp+组合数

2017-10-15 20:50 218 查看

题意

给出n,m,k,求出具有n个点、m条边、且前k个点的点度恰好为2的无向连通图个数,答案对109+7取模。

数据范围

n,m≤50,k≤2

解法

首先简化题目,我们考虑k=0的时候,那么有一个很经典的做法是DP。我们用dp[i][j]表示i个点m条边的连通图个数,那么答案明显是dp[n][m]。

接下来的转移我们考虑补集转化,我们枚举1号点所在的联通块点数和边数,那么

dp[i][j]=CjC2i−∑i−1k=1∑min(j,C2k)l=k−1dp[k][l]∗Ck−1i−1∗Cj−lC2i−k

那么我们已经完美解决了k=0的情况,接下来我们分析一下k=1的情况,由于1号点的度数为2,那么我们可以得出,删掉1号点及其连边,剩余的图要么只有1个联通块要么只有2个联通块。

对于只有1个联通块的情况,明显就是

dp[n−1,m−2]∗C2n−1

对于有2个联通块的情况,我们依然可以枚举2号点所在的联通块大小及边数,答案就是

∑n−2i=1∑min(C2i,m−2)j=i−1dp[i][j]∗dp[n−1−i][m−2−j]∗i∗(n−1−i)∗Ci−1n−2

于是k=1的情况也被解决了 作为一条咸鱼,我选择放弃k=2

其实k=2和k=1的情况差不多,只不过要讨论的情况变多了而已。说的简单啊喂

那么我们将1号点和2号点提出来,发现其余点和边构成的图的联通块个数只有1,2,3个。

当1号点与2号点相连的时候,联通块只可能为1或者2。

若联通块为1,那么答案就是

dp[n−2][m−3]∗(n−2)∗(n−2)

若联通块为2,其实也就等于了k=1的情况,不过我们要把答案×2,因为跟1号点连边和2号点连边是两种不同的情况。

2∗∑n−3i=1∑min(C2i,m−3)j=i−1dp[i][j]∗dp[n−2−i][m−3−j]∗i∗(n−2−i)∗Ci−1n−3

当1号点与2号点不相连的时候,若联通块个数为1,那么答案就是

dp[n−2][m−4]∗C2n−2∗C2n−2

若联通块个数为2,我们就枚举3号点所在的联通块大小及边数,那么答案是 啊公式真的好难打

∑n−3i=1∑min(C2i,k−4)j=i−1dp[i][j]∗dp[n−2−i][m−4−j]∗Ci−1n−3∗i∗(n−2−i)∗(2∗(C2i+C2n−2−i)+i∗(n−2−i) )

最后的那个括号里面的表示1个点连接两个联通块,另一个点要么两条边都在同一个联通块内,要么也连接两个联通块,注意后面的不×2。

若联通块个数为3,那么很明显1 2号线都要连接两个联通块,这时候我们枚举第1个联通块(设为K1),第二个联通块(K2)的点数和边数,那么第三个联通块(k3)的点数和边数也就确定了。说实话我觉得这个公式我要打半小时

∑n−4v1=1∑min(C2v1,m−4)e1=v1−1dp[v1][e1]∗Cv1n−2

∑v1+v2<=n−3v2=1∑min(C2v2,m−e1−4)e2=v2−1dp[v2][e2]∗Cv2n−2−v1

dp[n−2−v1−v2][m−4−e1−e2]

v1∗v2∗(n−2−v1−v2)∗(n−2)∗2

以上4行就是计算答案的过程了(自动在换行处补*)

最后那个式子v1*v2*(n-2-v1-v2)*(n-2)*2是这样算的,我们枚举1号点连接的两个联通块的方案数,再枚举2号点的,那么就有式子

v1∗v2∗(v1∗v3+v2∗v3)+v1∗v3∗(v1∗v2+v2∗v3)+v2∗v3∗(v1∗v2+v1∗v3)

合并一下就是

v1∗v2∗v3∗(v1+v2+v3)∗2=v1∗v2∗v3∗(n−2)∗2

到此为止这道题也就完美解决了

收获

这个题的入手点就是我们发现k很小,只有三种情况。

那么我们从简到难,先发现k=0的情况可以由DP解决。

再由限制的度数为2来推出除去限制点以外的联通块个数不会太多,于是我们分类讨论情况就可以了。

考点:

组合数 DP

易错点:

漏情况 边界(这个其实可以用一些技巧忽视掉) 少取膜

一个月以内我不会再写一篇公式这么多的题解了QAQ

#define mN 2510
#define mod 1000000007
#define ms(a,b) memset(a,b,sizeof(a))
#define ll long long
#define min(a,b) (a<b?a:b)
class KingdomAndCities {
public:
ll c[mN][61];
ll dp[61][61];
int howMany(int n, int k, int m) {
ms(c,0);
c[0][0]=1;
if (m<n-1) return 0;
for (int i=1; i<=n*n; i++) {
c[i][0]=1;
for (int j=1; j<=i; j++) c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
ms(dp,0);
for (int i=1; i<=n; i++)
for (int j=i-1; j<=min(c[i][2],m); j++) {
dp[i][j]=c[c[i][2]][j];
for (int k=1; k<=i-1; k++)
for (int l=k-1; l<=min(c[k][2],j); l++)
dp[i][j]=(dp[i][j]-dp[k][l]*c[i-1][k-1]%mod*c[c[i-k][2]][j-l]%mod+mod)%mod;
}
if (k==0) return dp
[m]%mod;
if (k==1) {
int ans=0;
ans+=dp[n-1][m-2]*c[n-1][2]%mod;
for (int i=1; i<=n-2; i++)
for (int j=i-1; j<=min(c[i][2],m-2); j++) {
ans=(ans+dp[i][j]*dp[n-1-i][m-2-j]%mod*i%mod*(n-1-i)%mod*c[n-2][i-1]%mod)%mod;
}
return ans%mod;
}
if (k==2) {
int ans=0;
ans=dp[n-2][m-3]*(n-2)%mod*(n-2)%mod;
for (int i=1; i<=n-3; i++)
for (int j=i-1; j<=min(c[i][2],m-3); j++) {
ans=(ans+2*dp[i][j]%mod*dp[n-2-i][m-3-j]%mod*i%mod*(n-2-i)%mod*c[n-3][i-1]%mod)%mod;
}
ans=(ans+dp[n-2][m-4]*c[n-2][2]%mod*c[n-2][2]%mod)%mod;
for (int i=1; i<=n-3; i++)
for (int j=i-1; j<=min(c[i][2],m-4); j++) {
ans=(ans+dp[i][j]*dp[n-2-i][m-4-j]%mod*i%mod*(n-2-i)%mod*c[n-3][i-1]%mod*((2*(c[i][2]+c[n-2-i][2])%mod+i*(n-2-i)%mod)%mod)%mod)%mod;
}
for (int v1=1; v1<=n-4; v1++)
for (int e1=v1-1; e1<=min(c[v1][2],m-4); e1++)
for (int v2=1; v1+v2<=n-3; v2++)
for (int e2=v2-1; e2<=min(c[v2][2],m-e1-4); e2++)
ans=(ans+dp[v1][e1]*c[n-3][v1-1]%mod*dp[v2][e2]%mod*c[n-3-v1][v2-1]%mod*dp[n-2-v1-v2][m-4-e1-e2]%mod*v1%mod*v2%mod*(n-2-v1-v2)%mod*(n-2)%mod*2%mod)%mod;
return ans;
}
return 0;
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息