hdu 3861 The King’s Problem

http://acm.hdu.edu.cn/showproblem.php?pid=3861

题意:给出一个有向图,问最少能够分成多少个区域,使得每个区域内的任意一对顶点X、Y间,要么X能达到Y,要么Y能到达X。

思路:如果图有环,那么环内的点都是满足的,所以先缩点。然后就是有向图的最小路径覆盖,这就是祼二分图解决。

PS:最小路径覆盖 = 点数-最大匹配。 缩点后点数不是原来的N。

View Code
#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;
}

 

 

 

 

posted on 2012-07-18 10:42  aigoruan  阅读(160)  评论(0)    收藏  举报

导航