lightoj 1210 最少加边,使得图变成强联通

来源:互联网 发布:写文档的软件 编辑:程序博客网 时间:2024/04/27 23:44

把一个图变成强联通,首先进行缩点,把原来的图变成很多的DAG,然后把所有出度为零的点和入度为零的点一一连起来,就得到了一个最少加边的强联通分量

#include<stdio.h>#include<vector>#include<algorithm>#include<stack>#include<string.h>using namespace std;#define MS(x) memset(x,0,sizeof(x))stack<int> S;vector<int> G[23000];vector<int> C[23000];bool used[25000];int dfn[25000];int low[25000];int time=0;int nv,ne;int cmp[25000];int ncmp;bool instack[25000];int in[25000];int out[25000];int init(){while(!S.empty()) S.pop();MS(used);MS(low);for(int i=0;i<25000;i++)dfn[i]=-1;time=0;ncmp=0;MS(cmp);MS(G);MS(C);MS(instack);MS(in);MS(out);}void tarjan(int n){dfn[n]=low[n]=time++;S.push(n);instack[n]=1;for(int i=0;i<G[n].size();i++){int v=G[n][i];if(dfn[v]==-1){tarjan(v);low[n]=min(low[n],low[v]);}else if(instack[v]){low[n]=min(low[n],dfn[v]);}}if(dfn[n]==low[n]){int v;do{v=S.top();S.pop();instack[v]=false;cmp[v]=ncmp;}while(v!=n);ncmp++;}}int main(){int cas;scanf("%d",&cas);for(int T=1;T<=cas;T++){init();scanf("%d%d",&nv,&ne);for(int i=0;i<ne;i++){int f,t;scanf("%d%d",&f,&t);f--;t--;G[f].push_back(t);}for(int i=0;i<nv;i++)if(dfn[i]==-1)tarjan(i);printf("Case %d: ",T);//printf("ncmp:%d\n",ncmp);if(ncmp==1){puts("0");continue;}for(int i=0;i<nv;i++){for(int j=0;j<G[i].size();j++){int v=G[i][j];int cn=cmp[i];int cv=cmp[v];if(cn!=cv)C[cn].push_back(cv);}}int ans=0;for(int i=0;i<ncmp;i++){out[i]=C[i].size();for(int j=0;j<C[i].size();j++){int v=C[i][j];in[v]++;}}int in0=0;int out0=0;for(int i=0;i<ncmp;i++){if(in[i]==0)in0++;if(out[i]==0)out0++;}printf("%d\n",max(in0,out0));}return 0;}


原创粉丝点击