hdu3861

/*
分析:
    把环缩点,求最小路径覆盖。
    果然比赛更激发潜能呀= =,以前很弱的时候见过这个题,
么a掉,今儿个虚拟赛1Y灭之。

                                           2013-05-21
*/








#include"iostream"
#include"cstdio"
#include"stack"
#include"cstring"
using namespace std;
const int N=5005;
const int M=100005;

int n,m;
int match[N],vis[N];
struct Edge{
    int u,v,next;
}edge[M],edge_n[M];
int tot,head[N],tot_n,head_n[N];
void add(int a,int b){
    edge[tot].u=a;edge[tot].v=b;edge[tot].next=head[a];head[a]=tot++;
}
void add_n(int a,int b){
    edge_n[tot_n].u=a;edge_n[tot_n].v=b;edge_n[tot_n].next=head_n[a];head_n[a]=tot_n++;
}

//Tarjan
int index_s,instack[N],DFN[N],LOW[N],belong[N],cnt;

stack<int>st;
void Tarjan(int k)
{
    int j,v;
    st.push(k);
    instack[k]=1;
    DFN[k]=LOW[k]=++index_s;
    for(j=head[k];j!=-1;j=edge[j].next)
    {
        v=edge[j].v;
        if(instack[v])  LOW[k]=LOW[k]>DFN[v]?DFN[v]:LOW[k];
        else if(DFN[v]==-1)
        {
            Tarjan(v);
            LOW[k]=LOW[k]>LOW[v]?LOW[v]:LOW[k];
        }
    }
    if(LOW[k]==DFN[k])
    {
        do
        {
            j=st.top();
            st.pop();
            instack[j]=0;
            belong[j]=cnt;
        }while(j!=k);
        cnt++;
    }
}

void build_new_map()
{
    int i;
    tot_n=0;
    memset(head_n,-1,sizeof(head_n));
    for(i=0;i<tot;i++)
    {
        if(belong[edge[i].u]==belong[edge[i].v])    continue;
        add_n(belong[edge[i].u],belong[edge[i].v]);
    }
}
void build_map()
{
    int i;
    int a,b;
    tot=0;
    memset(head,-1,sizeof(head));
    for(i=0;i<m;i++)
    {
        scanf("%d%d",&a,&b);
        add(a,b);
    }

    //缩点
    cnt=0;              //这个是新的编号
    index_s=0;
    memset(DFN,-1,sizeof(DFN));
    memset(LOW,-1,sizeof(LOW));
    memset(instack,0,sizeof(instack));
    for(i=1;i<=n;i++)   belong[i]=i;
    for(i=1;i<=n;i++)   if(DFN[i]==-1)  Tarjan(i);

    //构造新图
    build_new_map();
}
int dfs(int k)
{
    int j,v;
    for(j=head_n[k];j!=-1;j=edge_n[j].next)
    {
        v=edge_n[j].v;
        if(vis[v])  continue;
        vis[v]=1;
        if(match[v]==-1 || dfs(match[v]))
        {
            match[v]=k;
            return 1;
        }
    }
    return 0;
}
int main()
{
    int T;
    int i;
    cin>>T;
    while(T--)
    {
        scanf("%d%d",&n,&m);
        build_map();
        int ans=0;
        memset(match,-1,sizeof(match));
        for(i=0;i<cnt;i++)
        {
            memset(vis,0,sizeof(vis));
            ans+=dfs(i);
        }
        cout<<cnt-ans<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值