题解 —— 风纪委员

题目:

小爱作为风纪委员绝对不能容许扰乱风纪的事情出现!当然和小太的事情总是要在合适的时间和地点解决的~而且反正也得到了上面的许可外加声援什么的。

好吧扯远了~现在学校里有一些经常扰乱风纪的少年和少女~其中有些人是相互认识的,如果一个班里所有人都相互认识那么这个班的成员就会集体翘课。现在要把这些人分成两个人数相同的班级,小爱要知道两个班的人都会集体翘课的方案数有多少种。

题意:求将一张图分为两个完全图的方案数.

这题看似很难,但仔细琢磨一遍,发现:                                  还是很难!

定义两个集合 $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 }

 

posted @ 2019-04-13 14:44  QuickSilverX  阅读(365)  评论(0编辑  收藏  举报