Bonds
Total Submission(s): 309 Accepted Submission(s): 140
Problem Description
Given an undirected connected graph with
N
points and
An edge cut
A bond of a graph is an edge cut does not have any other edge cut as a proper subset.
Input
The first line of the input gives the number of test cases
T
;
Each test case consists of two integers:
N
,
limits
2<=N<=20
N−1<=M<=N∗(N−1)/2
Edges are distinct.
No edge connects to the point itself.
N
is larger than
Output
For each test case output “Case #x: y1 y2 … yN” (without quotes), where x is the test case number (starting from 1), and yi is the occurrence times in all bonds of i-th edge.
Sample Input
2
3 3
0 1
0 2
1 2
3 2
0 1
0 2
Sample Output
Case #1: 2 2 2
Case #2: 1 1
Hint
In first case, {(0,1),(0,2)} , {(0,1),(1,2)} , {(0,2),(1,2)} are bonds.
In second case, {(0,1)},{(0,2)} is bond.
Author
FZU
Source
2016 Multi-University Training Contest 4
题意:
给出一个
由
已知极小割边集恰好会将原图分成两块。
询问对于边
0 m−1
,每条边所在的极小割边集的个数
这题用位运算简直不能再精美(从QAQ巨那里学来的
首先题目要找对于每条边
u−v
所在的最小割边集的个数。
如果能找出G图中所有的连通图的个数,然后减去包含
u−v
边的连通图的个数,就是要找的答案。
接下来只要找出连通图的个数和包含u、v的连通图个数就可以了。
同时避免重复统计。
其他的都在代码(注释)里了~~~
#include <iostream>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <list>
#include <algorithm>
#include <map>
#include <set>
#define LL long long
#define Pr pair<int,int>
#define fread(ch) freopen(ch,"r",stdin)
#define fwrite(ch) freopen(ch,"w",stdout)
using namespace std;
const int INF = 0x3f3f3f3f;
const int msz = 1<<20;
const int mod = 1e9+7;
const double eps = 1e-8;
//Lowbit运算是个好东西,x拆成二进制后,返回低位第一个1所在的进制
//10010->10
//11000->1000
int lb(int x)
{
return x&(-x);
}
int cnt[msz];
int eg[msz];
//搜索点集S(二进制表示)是否为连通图
bool cal(int S)
{
//BFS的转换,now表示当前搜索的集合
int now = lb(S);
//vis跟vis数组一个意思,表示已经访问过的点集
int vis = 0;
int u;
//当now == vis时,表示已经没有多余的可访问的点了
//此时now表示的就是集合S中lb(S)所在的联通点集
while(now != vis)
{
//找到当前集合最低位的第一个未被访问的点
u = lb(now^vis);
//标记为访问过
vis |= u;
//将与该点直接相连且在S中的点加入当前集合
//eg数组在main中输入边的时候统计了
now |= eg[u]&S;
}
//如果S中每个点都被访问过了 那么S就是连通的
return vis == S;
}
int u[233],v[233];
int main()
{
//fread("");
//fwrite("");
int t;
scanf("%d",&t);
int n,m;
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]存放与u相连的点。u直接变为二进制,方便
eg[u[i]] |= v[i];
eg[v[i]] |= u[i];
}
int ans = 0;
for(int i = 0; i < tot; ++i)
{
//i&1是避免重复统计。
if((i&1) && cal(i) && cal(tot^i))
{
ans++;
cnt[i]++;
cnt[tot^i]++;
}
}
//cnt此时表示集合是否连通
//经过下面的操作 cnt[S]表示S集合所在的连通集的个数
//i枚举点
for(int i = 1; i <= tot; i <<= 1)
for(int j = 0; j <= tot; ++j)
if(j&i)
{
//将集合S所在的连通图个数赋予S^i(S中除去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]]);
}
puts("");
}
return 0;
}