zoukankan      html  css  js  c++  java
  • 2013长沙网赛 I题 Grand Prix

    比赛的时候没时间去看,赛后也是看了题解才过的。

    题目的意思是,给定二分图,判断哪些边是无用的,也就是一定不会在最大匹配中出现。

    解题思路:

    我们可以先跑一边匹配,因为点比较多,只能用HK来做。

    得到一个最大匹配后,枚举每条边,判断其是否为无用边。

    可以分情况考虑:

      设u,v为边的两端点。

      一、match[u]==v (即 match[v]==u)表示这条边为当前最大匹配的一条边,那肯定是可以用边。如果不是,则转到(2)。

      二、因为match[u]!=v (即 match[v]!=u )那么,可以分一下情况考虑:

        (1)match[u]==-1,也就是u尚未匹配,那么此时让u去匹配v,也一定不会导致最大匹配变小,所以该边为有用边。

        (2)match[v]==-1,思路同上。

        (3)match[u]!=-1 && match[v]!=-1 那么,如果让u匹配v,则会让match[u]和match[v]失去匹配对象,那么我们将得到一个匹配,失去两个匹配。此时,我们分析,只要: 

          1.match[v]到match[u]之间存在一条增广路,使match[v]匹配match[u]。

          2.存在某个点x(与u同为X部),match[x]==-1,能够找到一条增广路到达match[u],使得x匹配match[u]。

          3.存在某个点y(与v同为Y部),match[y]==-1,从match[v]出发,能够找到一条增广路到达y,使得match[v]匹配y。

          那么就可以补偿我们失去的一个匹配。

      解法:

      当然,每次枚举边去搜一次增广路的复杂度是很高的,我们可以通过预处理得到解。

      将原来的边转化,若ui匹配vi,则连边vi->ui,若ui不匹配vi,则ui->vi。

      这样,我们可以通过求强连通分量来判断条件1是否成立。

      bfs预处理出所有match[x]==-1的点能够到达的点判断条件2是否成立。

      将边反转一次,bfs预处理出match[y]==-1的点能够到达的点,判断条件3是否成立。

    #include    <iostream>
    #include    <cstdio>
    #include    <cstring>
    #include    <algorithm>
    #include    <queue>
    
    using namespace std;
    
    #define For(i,forN) for(int i=0;i<(forN);i++)
    #define Rep(i,forN) for(int i=(forN);i>=0;i--)
    #define ForEdge(i,u) for(int i=head[u];i!=-1;i=edge[i].next)
    #define sf  scanf
    #define pf  printf
    #define mp  make_pair
    #define _clr(x,y)   memset(x,y,sizeof(x))
    
    const int Maxn=101000,Maxe=Maxn*10;
    
    int match[Maxn],dis[Maxn],head[Maxn],etot,X,Y;
    int n,m;
    
    struct Edge
    {
        int to,next;
    }edge[Maxe];
    
    void init_edge()
    {
        etot=0;
        _clr(head,-1);
    }
    
    void add_edge(int u,int v)
    {
        edge[etot].to=v;
        edge[etot].next=head[u];
        head[u]=etot++;
    }
    
    bool bfs()
    {
        bool res=false;
        queue < int > q;
        For(i,n)    if(match[i]==-1)    q.push(i);
        _clr(dis,0);
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            for(int i=head[u];i!=-1;i=edge[i].next)
            {
                int v=edge[i].to;
                if(!dis[v])
                {
                    dis[v]=dis[u]+1;
                    if(match[v]==-1)
                    res=true;
                    else
                    {
                        dis[match[v]]=dis[v]+1;
                        q.push(match[v]);
                    }
                }
            }
        }
        return res;
    }
    
    bool find(int u)
    {
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to;
            if(dis[v]==dis[u]+1)
            {
                dis[v]=0;
                if(match[v]==-1 || find(match[v]))
                {
                    match[v]=u;
                    match[u]=v;
                    return true;
                }
            }
        }
        return false;
    }
    
    int HK()
    {
        int res=0;
        _clr(match,-1);
        while(bfs())
        {
            For(i,n)
            if(match[i]==-1 && find(i))
            res++;
        }
        return res;
    }
    
    int E[Maxe][2];
    bool Res[Maxe],vis[Maxn],nice[Maxn],canReach[2][Maxn];
    int bleg[Maxn],stk[Maxn],dfsn[Maxn],low[Maxn],vtime,scc,top;
    
    void tarjanDfs(int u)
    {
        vis[u]=true;    stk[top++]=u;
        dfsn[u]=low[u]=vtime++;
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to;
            if(!vis[v])
            {
                tarjanDfs(v);
                low[u]=min(low[u],low[v]);
            }
            else if(bleg[v]==-1)
                low[u]=min(low[u],dfsn[v]);
        }
        if(dfsn[u]==low[u])
        {
            do
            {
                bleg[stk[--top]]=scc;
            }while(stk[top]!=u);
            scc++;
        }
    }
    
    void Tarjan()
    {
        _clr(vis,false);    _clr(bleg,-1);
        vtime=top=0;
        For(i,n)
        if(!vis[i])
        tarjanDfs(i);
    }
    
    void Visit(int ind)
    {
        _clr(vis,false);    _clr(canReach[ind],false);
        queue < int > q;
        if(ind==0)
        {
            For(i,X)    if(match[i]==-1) q.push(i),vis[i]=true,canReach[ind][i]=true;
        }
        else
        {
            for(int i=X;i<n;i++)    if(match[i]==-1) q.push(i),vis[i]=true,canReach[ind][i]=true;
        }
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(int i=head[u];i!=-1;i=edge[i].next)
            {
                int v=edge[i].to;   canReach[ind][v]=true;
                if(!vis[v]) {vis[v]=true;q.push(v);}
            }
        }
    }
    
    int e[Maxe][2];
    
    void reserveEdge()
    {
        int tm=0;
        For(i,n)
        {
            ForEdge(j,i)
            {
                int v=edge[j].to;
                e[tm][0]=v; e[tm++][1]=i;
            }
        }
        init_edge();
        For(i,tm)
        {
            add_edge(e[i][0],e[i][1]);
        }
    }
    
    
    void solve()
    {
        init_edge();
        For(i,m)
        {
            int u=E[i][0],v=E[i][1];
            if(match[v]==u)
            {
                Res[i]=true;
                add_edge(v,u);
                //cout<<v<<" "<<u<<endl;
            }
            else
            {
                Res[i]=false;
                add_edge(u,v);
               // cout<<u<<" "<<v<<endl;
            }
        }
        n=X+Y;
        Tarjan();
        Visit(0);
        reserveEdge(); Visit(1);
        top=0;
        For(i,m)
        {
            if(!Res[i])
            {
                int u=E[i][0],v=E[i][1];
                if(match[u]==-1 || match[v]==-1 || bleg[v]==bleg[match[u]] || canReach[0][match[u]] || canReach[1][v] ) continue;
                else
                stk[top++]=i;
            }
        }
        pf("%d
    ",top);
        For(i,top)
        {
            if(i)   printf(" ");
            printf("%d",stk[i]);
        }
        puts("");
    }
    
    int CTN(char c)
    {
        if(c>='0' && c<='9')    return c-'0';
        return (int)(c-'A')+10;
    }
    
    int getNum(char *str)
    {
        int u=0;
        For(i,3)    u=u*32+CTN(str[i]);
        return u;
    }
    
    int main()
    {
        char str[20];
        while(~sf("%d%d%d",&X,&Y,&m))
        {
            n=X;
            init_edge();
            For(i,m)
            {
                sf("%s",str);
                int u=getNum(str),v=getNum(str+3)+X;
                add_edge(u,v);
                //cout<<u<<" "<<v<<endl;
                E[i][0]=u,E[i][1]=v;
            }
            HK();
            solve();
        }
        return 0;
    }
  • 相关阅读:
    【新梦想Java开发公开课】
    接口自动化框架httprunner(三)--断言
    接口自动化框架httprunner(二)--变量空间(context)作用域
    接口自动化框架httprunner(一)--安装及简单使用
    python+locust性能测试(四)之分布式运行
    安装Resharper 10.0.X 出现 The CrossAppDomainPointer is NULL 错误解决方案之一
    给DNN装SkinTuner扩展时出现Could not load file or assembly 'System.Data.SQLite
    STA和MTA线程模式的区别
    jQuery插件,迅速的实现拖拽功能
    query插件(三):Colorbox–内容播放插件
  • 原文地址:https://www.cnblogs.com/CooCoo/p/3405415.html
Copyright © 2011-2022 走看看