强连通分量+二分匹配

来源:互联网 发布:手机比价软件 编辑:程序博客网 时间:2024/06/14 10:08
<p>题 意是说一个有向图将n个点划分成最少的集合个数,要求任意两个相互到达的点在同一个几何中,且属于同一个集合的任意俩个点对(u,v),至少存在一条路 径,使得v对于u 可达 或者 u 对于v 可达。首先要缩点求集合的个数,然后重新构图,任意俩点,只要在同一条有向路径上,则可以属于一个集合,所以要在缩点后的图上用二分匹配找最小路径覆盖即 可。</p><p>最小路径覆盖=点数-最大匹配。这里点数是缩点之后的点数。</p>
#include <iostream># include<stdio.h># include<string.h># include<vector># include<algorithm>using namespace std;const int N = 5005;vector<int>s[N], s1[N];int n, m, stop, Bcnt, dindex;int DFN[N], Low[N], stap[N], belong[N], link[N], visit[N];bool instack[N];void tarjan(int i){    int j;    DFN[i] = Low[i] = ++ dindex;    instack[i] = true;    stap[++stop] = i;    for(j = 0; j < s[i].size(); j ++)    {        int k = s[i][j];        if(!DFN[k])        {            tarjan(k);            if(Low[k] < Low[i])                Low[i] = Low[k];        }        else if(instack[k] && Low[i] > DFN[k])            Low[i] = DFN[k];    }    if(DFN[i] == Low[i])    {        Bcnt++;        do        {            j = stap[stop--];            instack[j] = false;            belong[j]  = Bcnt;        }while(i != j);    }}void solve(){    stop = Bcnt = dindex = 0;    memset(DFN, 0, sizeof(DFN));    for(int i = 1; i <= n; i ++)        if(!DFN[i])            tarjan(i);}void deal(){    for(int i = 1; i <= n; i ++)    {        int t = belong[i];        for(int j = 0; j < s[i].size(); j ++)        {            int k = s[i][j];            int v = belong[k];            if(t != v)            {                s1[t].push_back(v);            }        }    }}bool get_num(int i){    for(int j = 0; j < s1[i].size(); j ++)    {        int k = s1[i][j];        if(!visit[k])        {            visit[k] = 1;            if(!link[k] || get_num(link[k]))            {                link[k] = i;                return true;            }        }    }    return false;}int hungery(){    int num = 0;    memset(link, 0, sizeof(link));    for(int i = 1; i <= Bcnt; i ++)    {        memset(visit, 0, sizeof(visit));        if(get_num(i))        num ++;    }    return Bcnt - num;}int main(){    int t;    scanf("%d", &t);    while(t --)    {        scanf("%d%d", &n, &m);        for(int i = 0; i <= n; i ++)        {            s[i].clear();            s1[i].clear();        }        for(int i = 0; i < m; i ++)        {            int x, y;            scanf("%d%d",&x, &y);            s[x].push_back(y);        }        solve();        deal();        int ans = hungery();        printf("%d\n", ans);    }    return 0;}

0 0
原创粉丝点击