转载声明:http://m.blog.csdn.net/article/details?id=52080217(代码)
转载声明:http://www.cnblogs.com/zufezzt/p/5723389.html (分析)
题意:
给你一副图,然后给你N条边,求出每条边成为极小割集的次数.
个人感想:
这是一道非常好的题,当然我不会…这道题的精髓在状压下的bfs.
好吧我们来分析下.
我一开始看到题解我也是迷惘的,不明白为什么枚举的是点集.
我们知道,如果用一个极小割集分出来的图,肯定有2个连通块.这两个连通块必然分别连通.这就相当于枚举了边集.顺理成章我们就知道了bond的个数Sum.
要这个有什么用呢?
我们想象,如果我们知道所有bond的个数,把不包含u-v的bond去掉就可以了啊.
Sum-cnt【u-v】代表总数减去 包含u-v的连通图.
所以通过枚举点集,把某一个点去掉cnt[i^j]+=cnt[i],就可以得到总数的点集了… 我们就可以直接得到答案.
虽然我没做出来,但是我感觉一下子,简简单单就学到了好多知识,真不难.
分析:状压DP +字节压缩.
ps:我总是觉得cnt[j^i] += cnt[j];这块会不会重复叠加,例如 【11101】可能会分成【11100】,【01101】叠带下去,然后【01100】就会加了2次,其实并不会,因为在这个过程中如果转移到了【01101】,可是【00001】这个点就已经不会出现,所以不可能把【01101】迭代消掉.
代码:
/* Author:GavinjouElephant
* Title:
* Number:
* main meanning:
*
*
*
*/
//#define OUT
#include <iostream>
using namespace std;
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <sstream>
#include <cctype>
#include <vector>
#include <set>
#include <cstdlib>
#include <map>
#include <queue>
//#include<initializer_list>
//#include <windows.h>
//#include <fstream>
//#include <conio.h>
#define MaxN 0x7fffffff
#define MinN -0x7fffffff
#define Clear(x) memset(x,0,sizeof(x))
const int INF=0x3f3f3f3f;
const int maxn=1<<20;
int T;
int N,M;
int lowerbit(int x)
{
return x&(-x);
}
int cnt[maxn];
int eg[maxn];
int u[maxn];
int v[maxn];
bool bfs(int S)
{
int now = lowerbit(S);
int vis = 0;
int u;
while(now != vis)
{
u = lowerbit(now^vis);
vis |= u;
now |= eg[u]&S;
}
return vis == S;
}
int main()
{
#ifdef OUT
freopen("coco.txt","r",stdin);
freopen("lala.txt","w",stdout);
#endif
scanf("%d",&T);
for(int z = 1; z <= T; z++)
{
scanf("%d%d",&N,&M);
int tot = (1<<N)-1;
memset(eg,0,sizeof(eg));
memset(cnt,0,sizeof(cnt));
for(int i = 0; i < M; i++)
{
scanf("%d%d",&u[i],&v[i]);
u[i] = 1<<u[i];
v[i] = 1<<v[i];
eg[u[i]] |= v[i];
eg[v[i]] |= u[i];
}
int ans = 0;
for(int i = 0; i < tot; ++i)
{
if((i&1) && bfs(i) && bfs(tot^i))
{
ans++;
cnt[i]++;
cnt[tot^i]++;
}
}
for(int i = 1; i <= tot; i <<= 1)
{
for(int j=tot; j>=0;j--)
{
if(j&i)
{
cnt[j^i] += cnt[j];
}
}
}
printf("Case #%d:",z);
for(int i = 0; i < M; i++)
{
printf(" %d",ans-cnt[u[i]|v[i]]);
}
printf("\n");
}
return 0;
}