标签:proving equivalences hdu 2767 强联通缩点
2 4 0 3 2 1 2 1 3
4 2
题意:n个点m条边,问最少添加多少条边使得整个图联通。
思路:先Tarjan求强联通分量,缩点,再求缩点后的点的入度和出度,入读为0的点的个数为a,出度为0的点的个数为b,ans=max(a,b)
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <string> #include <map> #include <stack> #include <vector> #include <set> #include <queue> #pragma comment (linker,"/STACK:102400000,102400000") #define mod 1000000009 #define INF 0x3f3f3f3f #define pi acos(-1.0) #define eps 1e-6 #define lson rt<<1,l,mid #define rson rt<<1|1,mid+1,r #define FRE(i,a,b) for(i = a; i <= b; i++) #define FREE(i,a,b) for(i = a; i >= b; i--) #define FRL(i,a,b) for(i = a; i < b; i++) #define FRLL(i,a,b) for(i = a; i > b; i--) #define mem(t, v) memset ((t) , v, sizeof(t)) #define sf(n) scanf("%d", &n) #define sff(a,b) scanf("%d %d", &a, &b) #define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c) #define pf printf #define DBG pf("Hi\n") typedef long long ll; using namespace std; const int MAXN = 20050;//点数 const int MAXM = 500050;//边数 struct Edge { int to,next; }edge[MAXM]; int head[MAXN],tot; int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];//Belong数组的值是1~scc int Index,top; int scc;//强联通分量的个数 bool Instack[MAXN]; int num[MAXN];//各个强联通分量包含的点的个数,数组编号为1~scc //num数组不一定需要,结合实际情况 void addedge(int u,int v) { edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++; } void Tarjan(int u) { int v; Low[u]=DFN[u]=++Index; Stack[top++]=u; Instack[u]=true; for (int i=head[u];i+1;i=edge[i].next) { v=edge[i].to; if (!DFN[v]) { Tarjan(v); if (Low[u]>Low[v]) Low[u]=Low[v]; } else if (Instack[v]&&Low[u]>DFN[v]) Low[u]=DFN[v]; } if (Low[u]==DFN[u]) { scc++; do{ v=Stack[--top]; Instack[v]=false; Belong[v]=scc; num[scc]++; }while (v!=u); } } void solve(int N) { memset(DFN,0,sizeof(DFN)); memset(Instack,false,sizeof(Instack)); memset(num,0,sizeof(num)); Index=scc=top=0; for (int i=1;i<=N;i++) //点的编号从1开始 if (!DFN[i]) Tarjan(i); } void init() { tot=0; memset(head,-1,sizeof(head)); } int n,m; int in[MAXN],out[MAXN]; int main() { #ifndef ONLINE_JUDGE freopen("C:/Users/asus1/Desktop/IN.txt","r",stdin); #endif int i,j,u,v,t; sf(t); while (t--) { sff(n,m); if(n==1){ //特判1(n==1,m==0) printf("0\n"); continue; } if(m==0){ //特判2( n==?,m==0) printf("%d\n",n); continue; } init(); for (i=0;i<m;i++) { sff(u,v); addedge(u,v); } solve(n); if(scc==1){ //如果强连通个数为1 printf("0\n"); continue; } mem(in,0); mem(out,0); for (int u=1;u<=n;u++) { for (i=head[u];i+1;i=edge[i].next) { int v=edge[i].to; if (Belong[u]!=Belong[v]) { out[Belong[u]]++; in[Belong[v]]++; } } } int ans,a=0,b=0; for (i=1;i<=scc;i++) { if (out[i]==0) a++; if (in[i]==0) b++; } ans=max(a,b); pf("%d\n",ans); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
Proving Equivalences (hdu 2767 强联通缩点)
标签:proving equivalences hdu 2767 强联通缩点
原文地址:http://blog.csdn.net/u014422052/article/details/46776327