HDU 3861 The King’s Problem 连通分量+二分匹配

来源:互联网 发布:淘宝开店在哪里注册 编辑:程序博客网 时间:2024/05/19 02:16

题意:n个城市,m条有向边, 现在要把这个图分成块,对于块的定义:1,所有能够互通的点一定在一个块内。2,一个点可以到达另一个点,所经过的点只能是这个块内的。问做少要分多少个块?


想法:显然tarjan先缩点,然后可以想到,要想百分之一百满足第2个条件,那么每一个块最多只能有所点后的两个点,所以对所得的缩点进行二分匹配,然后求得最大独立集=col-(最大匹配数)


#include<iostream>#include<cstdio>#include<cstring>#include<stack>#include<vector>using namespace std;const int nodes=5000+5;const int edges=100000+50;int n,m;struct node{    int v,next;}e[edges];vector<int>ve[nodes];stack<int>s;int head[nodes],cnt;int link[nodes],vis[nodes];int dfn[nodes],low[nodes],instack[nodes],paint[nodes];int index,col;void Init(){     memset(head,-1,sizeof(head));     memset(dfn,0,sizeof(dfn));     memset(low,0,sizeof(low));     while(!s.empty()) s.pop();     for(int i=1;i<=n;i++)     ve[i].clear();     memset(instack,0,sizeof(instack));     memset(paint,0,sizeof(paint));     index=col=1;      cnt=0;} void add(int a,int b){    e[cnt].v=b;    e[cnt].next=head[a];    head[a]=cnt++;}int Min(int a,int b){    if(a<b) return a;    return b;}void tarjan(int u){    dfn[u]=low[u]=index++;    instack[u]=1;    s.push(u);    for(int i=head[u];i+1;i=e[i].next)    {        int v=e[i].v;        if(!dfn[v])        {            tarjan(v);            low[u]=Min(low[u],low[v]);        }        else if(instack[v])        {            low[u]=Min(low[u],dfn[v]);        }    }    if(low[u]==dfn[u])    {        int k=s.top();        while(k!=u)        {            s.pop();            instack[k]=0;            paint[k]=col;            k=s.top();        }        s.pop();        instack[u]=0;        paint[u]=col;        col++;    }}void tarjan_slove(){    for(int i=1;i<=n;i++)    {        if(!dfn[i]) tarjan(i);    }    col--;}void build_map(){    for(int i=1;i<=n;i++)    {        for(int j=head[i];j+1;j=e[j].next)        {            int a=i,b=e[j].v;            if(paint[a]!=paint[b])            {                ve[paint[a]].push_back(paint[b]);            }        }    }}int dfs(int u){    for(int i=0;i<ve[u].size();i++)    {        int v=ve[u][i];        if(!vis[v])        {            vis[v]=1;            if(link[v]==-1||dfs(link[v]))            {                link[v]=u;                return 1;            }        }    }    return 0;}void slove(){    memset(link,-1,sizeof(link));    int res=0;    for(int i=1;i<=col;i++)    {        memset(vis,0,sizeof(vis));        res+=dfs(i);    }    printf("%d\n",col-res);}int main(){    int test;    scanf("%d",&test);    while(test--)    {        scanf("%d%d",&n,&m);        Init();        for(int i=1;i<=m;i++)        {            int a,b;            scanf("%d%d",&a,&b);            add(a,b);        }        tarjan_slove();        build_map();        slove();    }    return 0;}

1 0
原创粉丝点击