HDU 3861 The King’s Problem(强连通分量+最小路径覆盖)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3861

题目大意:

在csdn王国里面, 国王有一个新的问题. 这里有N个城市M条单行路,为了让他的王国更加高效,国王想要将他的王国划分成几个州,
每个城市必须属于一个州。对于两个城市(u,v),如果有一条从u到v的路,也有一条从v到u的路,那么u、v必须属于同一个州。
对于每一个州里的任何两个城市u、v,都有不经过其他州的路从u到v或从v到u。现在国王想要知道他的王国最少可以划分成多少个州。

解题思路:

因为“能相互到达的点必须属于同一个州”所以先用强连通分量缩点。然后就是求最小路径覆盖了,思路很清晰,但我没想出来。。。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
using namespace std;
const int N=5e3+5;

int n,m,cnt,num,uN;
int dfn[N],low[N],fa[N],link[N];
bool vis[N];
stack<int>sk;
vector<int>v[N];
vector<int>g[N];

void tarjan(int u){
    dfn[u]=low[u]=++cnt;
    sk.push(u);
    for(int i=0;i<v[u].size();i++){
        int t=v[u][i];
        if(!dfn[t]){                                        //点t未被访问
            tarjan(t);
            low[u]=min(low[u],low[t]);
        }
        else if(!fa[t])  low[u]=min(low[u],dfn[t]);         //点t已被访问,且t还在栈中
    }
    if(low[u]==dfn[u]){
        num++;
        while(1){
            int t=sk.top();
            sk.pop();
            fa[t]=num;                                      //缩点操作,将这些点都归为点num
            if(t==u) break;
        }
    }
}

bool dfs(int u){
    for(int i=0;i<g[u].size();i++){
        int t=g[u][i];
        if(!vis[t]){
            vis[t]=true;
            if(link[t]==-1||dfs(link[t])){
                link[t]=u;
                return true;
            }
        }
    }
    return false;
}

int max_match(){
    memset(link,-1,sizeof(link));
    int ans=0;
    for(int i=1;i<=uN;i++){
        memset(vis,false,sizeof(vis));
        if(dfs(i)) ans++;
    }
    return ans;
}

void init(){
    cnt=num=0;
    memset(fa,0,sizeof(fa));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    for(int i=0;i<=n;i++){
        v[i].clear();
        g[i].clear();
    }
}

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        init();
        for(int i=1;i<=m;i++){
            int a,b;
            scanf("%d%d",&a,&b);
            v[a].push_back(b);
        }
        for(int i=1;i<=n;i++){
            if(!dfn[i]) tarjan(i);
        }
        //缩点建新图
        for(int i=1;i<=n;i++){
            for(int j=0;j<v[i].size();j++){
                int t=v[i][j];
                if(fa[t]!=fa[i]) g[fa[t]].push_back(fa[i]);
            }
        }
        uN=num;
        printf("%d\n",num-max_match());
    }
    return 0;
}

 

posted @ 2018-04-11 00:28  Yeader  阅读(184)  评论(0编辑  收藏  举报