bzoj 4671: 异或图
4671: 异或图
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 61 Solved: 39
[Submit][Status][Discuss]
Description
定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与
G2 中的出现次数之和为 1, 那么边 (u, v) 在 G 中, 否则这条边不在 G 中.
现在给定 s 个结点数相同的图 G1...s, 设 S = {G1, G2, . . . , Gs}, 请问 S 有多少个子集的异
或为一个连通图?
Input
第一行为一个整数s, 表图的个数.
接下来每一个二进制串, 第 i 行的二进制串为 gi, 其中 gi 是原图通过以下伪代码转化得
到的. 图的结点从 1 开始编号, 下面设结点数为 n.
Algorithm 1 Print a graph G = (V, E)
for i = 1 to n do
for j = i + 1 to n do
if G contains edge (i, j) then
print 1
else
print 0
end if
end for
end for
2 ≤ n ≤ 10,1 ≤ s ≤ 60.
Output
输出一行一个整数, 表示方案数
Sample Input
3
1
1
0
1
1
0
Sample Output
4
这个题还不很明白,对斯特林数还不够了解
#include<iostream> #include<cstdio> #include<cstring> #define maxn 20 using namespace std; int co[maxn],n,m,s,tot; long long fac[maxn],two[70],eq[70],ans; bool dis[70][maxn][maxn]; char h[maxn*maxn]; void dfs(int x,int m){ if(x==n+1){ int top=0; for(int i=1;i<=n-1;i++) for(int j=i+1;j<=n;j++){ if(co[i]!=co[j]){ long long t=0; for(int k=1;k<=s;k++)if(dis[k][i][j])t+=two[k-1]; for(int k=1;k<=top;k++)if((t^eq[k])<t)t^=eq[k]; if(t)eq[++top]=t; } } ans+=fac[m-1]*two[s-top]; return; } for(int i=1;i<=m+1;i++){ co[x]=i; dfs(x+1,m+(i>m)); } } int read(){ char ch=getchar(); while (ch<'0'||ch>'1') ch=getchar(); return ch-'0'; } int main(){ scanf("%d%s",&s,h+1); int len=strlen(h+1); for(n=1;n<=10;n++)if(n*(n-1)/2==len)break; long long t=0; for(int i=1;i<=n-1;i++) for(int j=i+1;j<=n;j++) dis[1][i][j]=h[++t]-'0'; for(int k=2;k<=s;k++) for(int i=1;i<=n-1;i++) for(int j=i+1;j<=n;j++) dis[k][i][j]=read(); fac[0]=two[0]=1; for(int i=1;i<=n;i++)fac[i]=-1LL*fac[i-1]*i; for(int i=1;i<=s;i++)two[i]=two[i-1]*2; dfs(1,0); cout<<ans<<endl; }