hdu 3861 The King’s Problem
http://acm.hdu.edu.cn/showproblem.php?pid=3861
题意:给出一个有向图,问最少能够分成多少个区域,使得每个区域内的任意一对顶点X、Y间,要么X能达到Y,要么Y能到达X。
思路:如果图有环,那么环内的点都是满足的,所以先缩点。然后就是有向图的最小路径覆盖,这就是祼二分图解决。
PS:最小路径覆盖 = 点数-最大匹配。 缩点后点数不是原来的N。

#include<set> #include<map> #include<stack> #include<queue> #include<cmath> #include<bitset> #include<string> #include<climits> #include<cstdio> #include<vector> #include<utility> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define IN puts("in") #define OUT puts("out") #define FR(x) freopen(x,"r",stdin) #define FW(x) freopen(x,"w",stdout) #define MSET(x,y) memset(x,y,sizeof(x)) #define ST system("pause") #define lowbit(x) (x)&(-x) #define L(x) (x)<<1 #define R(x) ((x)<<1)^1 #define MM (l + r) >> 1 #define LL (rt)<<1 #define RR ((rt)<<1)^1 using namespace std; const int maxn = 5005; struct nd { int u,v,next; }edge[maxn*20]; int head[maxn],vis[maxn],dfn[maxn],low[maxn],belong[maxn],st[maxn],Link[maxn]; int ecnt,cnt,tp,idx; void add(int u,int v) { edge[ecnt].u = u; edge[ecnt].v = v; edge[ecnt].next = head[u]; head[u] = ecnt++; } void init() { ecnt = cnt = tp = idx = 0; MSET(head,-1); MSET(vis,0); MSET(dfn,0); MSET(Link,0); } void readin(int n,int m) { int u,v; while(m--){ scanf("%d %d",&u,&v); add(u,v); } } void tarjan(int u) { int i,v; dfn[u] = low[u] = ++idx; vis[u] = 1; st[++tp] = u; for(i = head[u]; i != -1; i = edge[i].next){ v = edge[i].v; if(!dfn[v]){ tarjan(v); low[u] = min(low[v],low[u]); }else if(vis[v])low[u] = min(dfn[v],low[u]); } if(dfn[u]==low[u]){ ++cnt; do{ v = st[tp--]; vis[v] = 0; belong[v] = cnt; }while(v^u); } } bool dfs(int u) { int i,v; for(i = head[u]; i != -1; i = edge[i].next) { v = edge[i].v; if(vis[v])continue; vis[v] = 1; if(Link[v]==0||dfs(Link[v])){ Link[v] = u; return true; } }return false; } void processing(int n,int m) { int k = 0; for(int i = 1; i <= n; ++ i) if(!dfn[i]) tarjan(i); ecnt = 0; MSET(head,-1); for(int i = 0; i < m; ++ i){ int u = belong[edge[i].u]; int v = belong[edge[i].v]; if(u^v)add(u,v); } for(int i = 1; i <= cnt; ++ i){ MSET(vis,0); if(dfs(i))++k; } printf("%d\n",cnt-k); } int main() { int t,n,m; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); init(); readin(n,m); processing(n,m); } return 0; }