hdu 5765 Bonds 状压


Bonds

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 424    Accepted Submission(s): 203


Problem Description
Given an undirected connected graph with N points and M edges. ?? wants to know the number of occurrence in all bonds of graph for every edge.The index of points starts from 0.
An edge cut E of a Graph G is a set of edges of G and the G would be disconnected after deleting all the edges of E.
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; T test cases follow.
Each test case consists of two integers: N, M, followed by M lines, each line contains two integers u, v, implying an undirected edge between u and v.

limits
T <= 20
2 <= N <= 20
N-1 <= M <= N*(N-1)/2
Edges are distinct.
No edge connects to the point itself.
N is larger than 10 in no more than 5 cases.
 

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
 

Recommend
wange2014   |   We have carefully selected several similar problems for you:   5792  5791  5790  5789  5788 
 

Statistic |  Submit |  Discuss |  Note


题意:给出一幅点数极少的图,问每条边在多少个极小割之内。


解:去掉任意一个极小割之后对应两个连通块

      对于任意一条边的答案,用所有极小割的数量减去这条边所在连通块的数量即可。



#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;

#define all(x) (x).begin(), (x).end()
#define for0(a, n) for (int (a) = 0; (a) < (n); (a)++)
#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)
#define mes(a,x,s)  memset(a,x,(s)*sizeof a[0])
#define mem(a,x)  memset(a,x,sizeof a)
#define ysk(x)  (1<<(x))
typedef long long ll;
typedef pair<int, int> pii;
const int INF =0x3f3f3f3f;
const int maxn= 20   ;
const int maxm=200;
const int maxS=1048576;
int n,m,all,G[maxS+5],u[maxm+5],v[maxm+5],S,sum[maxS+5];
bool connected[maxS+3];



inline void add_edge(int ind,int x,int y)
{
       u[ind]=x,v[ind]=y;
       G[ysk(x)]|=ysk(y);
       G[ysk(y)]|=ysk(x);
}

int lowbit(int x)
{
    return x&(-x);
}

int main()
{
   std::ios::sync_with_stdio(false);
   int T,x,y,kase=0;cin>>T;
   while(T--)
   {
      cin>>n>>m;
      //得到邻接表(状压)
      memset(G,0,sizeof G);
      for0(i,m)
      {
          cin>>x>>y;
          add_edge(i,x,y);
      }

      //最大状态
      S=ysk(n)-1;
      //对于每个点集s,得到能够到达的点集G[s]
      for(int s=1;s<=S;s++)
      {
          int s2=s^lowbit(s);
          G[s]=G[s2]|G[lowbit(s)];

      }

      //判断点集s是否连通
      memset(connected,0,sizeof connected);
      queue<int>q;
      for0(i,n) q.push(ysk(i) ),connected[ysk(i)]=1;
      while(!q.empty())
      {
          int x=q.front();q.pop();
          int s=G[x]&(~x);//点集x可到达的点集 ,不包括x自身
          while(s)
          {
              int s2=lowbit(s)|x;
              if(!connected[s2])
              {
                  connected[s2]=1;
                  q.push(s2);
              }
              s-=lowbit(s);
          }
      }


      //初始化
      all=0;
      memset(sum,0,sizeof sum);
      for1(s1,S-1)
      {
          int s2=S-s1;
          if(s1<s2&&connected[s1]&&connected[s2]   )//极小割,分割出去之后应该是正好两个连通块
          {
               sum[s1]++,sum[s2]++,all++;
          }
      }

      //统计边集内的点共在多少个连通分量中出现。
      //动态规划
      for0(j,n)
      {
          for(int s=S-1;s;s--)  if( !(s&ysk(j)) )
          {
              sum[s]+=sum[s|ysk(j) ];
          }
      }

     //输出答案
      printf("Case #%d:",++kase);
      for0(i,m)
      {
          printf(" %d",all-sum[ ysk(u[i])|ysk(v[i])  ] );//所有极小割数量减去边i不在极小割内的数量。
      }
      putchar('\n');





   }
   return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值