U626763 小D的奶牛

题目背景

暑假,小D去了一个神奇的岛屿度假,在这个岛上有一群有神奇的奶牛。

题目描述

岛屿上的奶牛一共有$N$只,每一天,有一部分奶牛去工作,另一部分奶牛去玩乐。哪些奶牛去工作由奶牛首领决定。 奶牛们都是暴躁老哥,一旦工作安排使他们不满就会发生暴动;具体来说如果某天去工作的奶牛中存在两只奶牛不是朋友关系,它们就会烦躁;或者某天的工作安排和之前某天相同,他们会厌倦,这两种情况下就会暴动。 显然,暴动是一定会发生的。奶牛首领想要暴动尽量晚发生,向小D询问暴动最晚的发生时间;但小D还要忙着颓废,于是把这个问题交给了你。

输入格式

第一行一个整数$N$,描述奶牛的数量。 接下来$N$行,每行$N$个0/1字符描述关系矩阵$A$。 若$A_{i,j}=1$表示$i$和$j$是朋友关系。 保证$A_{i,j}=A_{j,i}$,$A_{i,i}=0$

输出格式

输出到文件`cows.out`中。 一行一个整数$Ans$,奶牛最晚发生暴动的时间。

说明/提示

对于$10\%$的数据,$N\leq 9$ 对于$30\%$的数据,$N\leq 20$ 另有$20\%$的数据, 每个奶牛的朋友数量不超过$ 20$ 对于$100\%$的数据,$N\leq 50$ ## 10%: 暴力; ## $n\le20$:状压dp; ## 另外20%数据: 团的大小$\leq 21$: 枚举团上编号最小的点,然后同上一部分; ## 正解 考虑Meet in the middle: 先考虑前$N / 2$个点,求出每种取点方式是否能形成一个团; 再考虑后$N / 2$个点,求出每种取点方式有多少个子集是一个团; 枚举每个前部分的点的选取方式,然后求出后半部分有哪些点和它们都有边; 然后后半部分能取的集合的数量就是,后半部分那些点的子集中形成的团的数量; $O(N * 2 ^ (N / 2))$ std ```cpp #include #include using namespace std; const int MAX = 50; const int MANY = 1 > n; int n1 = n/2; int n2 = (n+1)/2; assert(1 c; M[i][j] = c -'0'; if (i > j) assert(M[i][j] == M[j][i]); if (M[i][j]==0) continue; if (i < n1 && j < n1) Adj1[i] |= 1 = n1) Adj12[i] |= 1 = n1 && j >= n1) Adj2[i] |= 1