标签:the kings problem hdu 3861 强连通缩点 最小路径覆盖
1 3 2 1 2 1 3
2
题意:n个城市m条有向边,把这些城市分成若干个州,分的原则是(1)u和v可以互相到达的话他们两个必须在同一个州(2)同一个州里任意两个城市u和v要满足u可以到达v或者v可以到达u。问州的最小个数是多少。
思路:先用Tarjan算法进行缩点,在缩点后的图上进行二分图匹配,最后求得最小路径覆盖=强连通个数-最大匹配数。
可以看一下:
http://blog.csdn.net/hellobabygogo3/article/details/7900812
http://www.cnblogs.com/ka200812/archive/2011/07/31/2122641.html
代码:
#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 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; #define INF 0x3f3f3f3f #define mod 1000000009 const int maxn = 1005; const int MAXN = 5005; const int MAXM = 100010; int n,m; struct Edge { int to,next; }edge[MAXM],e[MAXM]; int head[MAXN],tot; int Low[MAXN],DFN[MAXN],Belong[MAXN],Stack[MAXN]; int Index,scc,top; bool Inq[MAXN]; int uN,vN; int linker[MAXN]; bool used[MAXN]; int hed[MAXN],num; void init() { tot=0;num=0; memset(hed,-1,sizeof(hed)); memset(head,-1,sizeof(head)); } void add(int u,int v) { e[num].to=v; e[num].next=hed[u]; hed[u]=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; Inq[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 (Inq[v]&&Low[u]>DFN[v]) Low[u]=DFN[v]; } if (Low[u]==DFN[u]) { scc++; do{ v=Stack[--top]; Inq[v]=false; Belong[v]=scc; }while (v!=u); } } void solve(int N) { memset(DFN,0,sizeof(DFN)); memset(Inq,false,sizeof(Inq)); Index=scc=top=0; for (int i=1;i<=N;i++) if (!DFN[i]) Tarjan(i); for (int u=1;u<=N;u++) { for (int i=head[u];~i;i=edge[i].next) { int v=edge[i].to; if (Belong[u]==Belong[v]) continue; add(Belong[u],Belong[v]); } } uN=vN=scc; } bool dfs(int u) { for (int i=hed[u];~i;i=e[i].next) { int v=e[i].to; if (!used[v]) { used[v]=true; if (linker[v]==-1||dfs(linker[v])) { linker[v]=u; return true; } } } return false; } int hungary() { int ans=0; memset(linker,-1,sizeof(linker)); for (int i=1;i<=uN;i++) { memset(used,false,sizeof(used)); if (dfs(i)) ans++; if (ans==uN) break; } return ans; } int main() { #ifndef ONLINE_JUDGE freopen("C:/Users/lyf/Desktop/IN.txt","r",stdin); #endif int i,j,t,u,v; sf(t); while (t--) { sff(n,m); init(); for (i=0;i<m;i++) { sff(u,v); addedge(u,v); } solve(n); int ans=hungary(); printf("scc=%d \n",scc); printf("%d\n",scc-ans); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
The King’s Problem (hdu 3861 强连通缩点+最小路径覆盖)
标签:the kings problem hdu 3861 强连通缩点 最小路径覆盖
原文地址:http://blog.csdn.net/u014422052/article/details/47205335