题目:
小爱作为风纪委员绝对不能容许扰乱风纪的事情出现!当然和小太的事情总是要在合适的时间和地点解决的~而且反正也得到了上面的许可外加声援什么的。
好吧扯远了~现在学校里有一些经常扰乱风纪的少年和少女~其中有些人是相互认识的,如果一个班里所有人都相互认识那么这个班的成员就会集体翘课。现在要把这些人分成两个人数相同的班级,小爱要知道两个班的人都会集体翘课的方案数有多少种。
题意:求将一张图分为两个完全图的方案数.
这题看似很难,但仔细琢磨一遍,发现: 还是很难!
定义两个集合 $A,B$,对应两个完全图
发现若两个点 $a,b$ 若无连边,两个点就不可能在同一集合内
这就启发我们将所有没有连边的关系重新建成一张图 $G‘$ ,即补图
很明显 $G‘$ 有可能不连通。
由于这张图上同一条边连接的两个点不可能在一个集合内,即这是一张二分图,我们可以对它染黑白色。
当然,如果一个连通块不是二分图(即存在边数 $>1$ 的奇环),输出 $0$
(染色随便染)
处理完每个连通块后,由于实际黑色的个数是等于白色的个数的,所以我们需要对某些连通块反色
定义状态 $F[i][j]$ 表示做到第 $i$ 个块颜色个数差为 $j$ 的方案数
有两种不同决策:将连通块内黑色丢入 $A$ 或 $B$,白色相反
于是有了下列转移方程
$F[i][j] = (F[i-1][abs(j - a[i] + b[i])] + F[i-1][abs(j - a[i] + b[i])])$
巨佬要滚数自己滚吧,忘记说了 $n <= 100$
Code:
1 #include<cstring> 2 #include<cstdio> 3 #define R register 4 #define MAXN 110 5 #define mod 1000000007 6 #define abs(_a) ((_a)<0?-(_a):_a) 7 using namespace std; 8 int n,m,cnt = 0; 9 struct BLOCK{ 10 int a,b; 11 }B[MAXN]; 12 int from[MAXN],col[MAXN]; 13 bool G[MAXN][MAXN],flag; 14 int sks,slr; 15 int dp[MAXN][MAXN]; 16 void dfs(int u,int g) 17 { 18 from[u] = cnt; 19 col[u] = g; 20 g ? ++sks : ++slr; 21 for(R int i = 1; i <= n; i++) 22 { 23 if(flag) return; 24 if(col[i] == g && !G[i][u] && from[i] && i != u) //存在奇环 25 { 26 puts("0"); 27 flag = 1; 28 return; 29 } 30 if(from[i]) continue; 31 if(!G[i][u])dfs(i,g^1); 32 } 33 } 34 int main() 35 { 36 memset(col,-1,sizeof(col)); 37 scanf("%d%d",&n,&m); 38 for(R int i = 1; i <= m; i++) 39 { 40 int u,v; 41 scanf("%d%d",&u,&v); 42 G[u][v] = G[v][u] = true; 43 } 44 for(R int i = 1; i <= n; i++) 45 { 46 if(from[i]) continue; 47 ++cnt; 48 sks = slr = 0; 49 dfs(i,0); 50 if(flag) return 1 ^ 1; 51 B[cnt].a = sks; 52 B[cnt].b = slr; 53 } 54 dp[0][0] = 1; 55 for(R int i = 1; i <= cnt; i++) 56 for(R int j = 0; j <= n; j++) 57 { 58 dp[i][j] = (dp[i-1][abs(j+B[i].a-B[i].b)] + dp[i-1][abs(j-B[i].a+B[i].b)])%mod; 59 } 60 printf("%d",dp[cnt][0]); 61 return 0; 62 }
原文:https://www.cnblogs.com/QuickSilverX/p/10701114.html