UVALive 4287 Proving Equivalences(缩点)

等价性问题,给出的样例为 a->b的形式,问要实现全部等价(即任意两个可以互相推出),至少要加多少个形如 a->b的条件。

容易想到用强连通缩点,把已经实现等价的子图缩掉,最后剩余DAG。要推出一个方案,YY后取“出度为零”和“入度为零”的点数的较大值。

理由:假定出度为零的点数较多,即是我们通常意义上的树的形式(当然,DAG是图,这里只是类比)。

根可以推出其所有子孙,事实上任意一个点都可以推出其子孙,那么只要让该节点推出树根,就可以推出整棵树上所有的节点了。那么多棵树为什么不是相乘呢?,借题目中的范例,a->b,b->c,c->a,形成一个循环即可。

本质:给定一个有向图,问是否加上多少条边,使原图构成强连通。

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stack>
  4 #include<algorithm>
  5 using namespace std;
  6 
  7 const int MAXN=55555;
  8 
  9 struct Edge{
 10     int v,next;
 11     Edge(){}
 12     Edge(int _v,int _next):v(_v),next(_next){}
 13 }edge[MAXN];
 14 
 15 int tol,head[MAXN];
 16 int low[MAXN],dfn[MAXN],sccno[MAXN],scc_cnt,TT;
 17 
 18 stack<int >stk;
 19 
 20 void init()
 21 {
 22     tol=0;
 23     memset(head,-1,sizeof(head));
 24 }
 25 
 26 void add(int u,int v)
 27 {
 28     edge[tol]=Edge(v,head[u]);
 29     head[u]=tol++;
 30 }
 31 
 32 void dfs(int u)
 33 {
 34     int v;
 35     dfn[u]=low[u]=++TT;
 36     stk.push(u);
 37     for(int i=head[u];i!=-1;i=edge[i].next)
 38     {
 39         v=edge[i].v;
 40         if(!dfn[v]){
 41             dfs(v);
 42             low[u]=min(low[u],low[v]);
 43         }else if(!sccno[v]){
 44             low[u]=min(low[u],dfn[v]);
 45         }
 46     }
 47     if(low[u]==dfn[u]){
 48         scc_cnt++;
 49         do{
 50             v=stk.top();
 51             stk.pop();
 52             sccno[v]=scc_cnt;
 53         }while(v!=u);
 54     }
 55 }
 56 
 57 void tarjan(int n)
 58 {
 59     scc_cnt=TT=0;
 60     memset(low,0,sizeof(low));
 61     memset(dfn,0,sizeof(dfn));
 62     memset(sccno,0,sizeof(sccno));
 63 
 64     while(!stk.empty())
 65         stk.pop();
 66     for(int i=1;i<=n;i++)
 67         if(!dfn[i])
 68             dfs(i);
 69 }
 70 
 71 int main()
 72 {
 73     int T,n,m;
 74     int a[MAXN],b[MAXN];
 75     scanf("%d",&T);
 76     while(T--)
 77     {
 78         scanf("%d%d",&n,&m);
 79 
 80         init();
 81         for(int i=0;i<m;i++)
 82         {
 83             scanf("%d%d",&a[i],&b[i]);
 84             add(a[i],b[i]);
 85         }
 86 
 87         tarjan(n);
 88 
 89         int in[MAXN],out[MAXN];
 90         memset(in,0,sizeof(in));
 91         memset(out,0,sizeof(out));
 92         for(int i=0;i<m;i++)
 93         {
 94             if(sccno[a[i]]!=sccno[b[i]]){
 95                 in[sccno[b[i]]]++;
 96                 out[sccno[a[i]]]++;
 97             }
 98         }
 99 
100         int innum,outnum;
101         innum=outnum=0;
102         for(int i=1;i<=scc_cnt;i++)
103         {
104             if(!in[i])
105                 innum++;
106             if(!out[i])
107                 outnum++;
108         }
109 
110         if(scc_cnt==1)printf("0\n");
111         else printf("%d\n",max(innum,outnum));
112     }
113     return 0;
114 }
View Code

 

posted @ 2013-08-06 08:45  Thousand Sunny  阅读(260)  评论(0编辑  收藏  举报