zoukankan      html  css  js  c++  java
  • hdu3861(tarjan缩点+最小路径覆盖)

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

    题意:有n个城市,m条路(有方向的),国王想把n个城市划最少个数的州,便于管理。两两相连的城市一定划为一个州,在同一个州的任意两个城市相互之间至少要有一条路径到达,即u到达v或v到达u;每个点都只能在一个州里。问最少需要划分多少个州。

     

    思路:先将n个城市用tarjan算出强联通分量,并将同一连通分量的城市归为一类,一个强连通分量就相当于一个点(可以看作一个城市)。再算出点与点是否相连(两个相连的点可以为一个州),有二分图匹配(匈牙利算法)算出最大匹配数,答案就是强联通分量数减去最大匹配数。

    为什么答案是强联通分量数减去最大匹配数?

    我们可以这样想,我们先把一个强联通分量的所有城市看作一个点(要缩点)(可看成一个城市),点与点之间相连就可以划分一个州,这是最后的情况,这样这个州的城市都至少有一条路这个到那个。问题是要最少的州,那么我们二分图匹配,算出可以匹配的点,剩下的不可以匹配的就是答案了,所以答案就是强联通分量数减去最大匹配数。

     

    代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #define maxn 100050
    using namespace std;
    struct node{
        int v,nxt;
    }edge[maxn],e[maxn];
    int head[maxn],low[maxn],dfn[maxn],vis[maxn],stack[maxn];
    int top,cnt,scs,num,ans;
    int used[maxn],f[maxn],rt[maxn],x[maxn],y[maxn],newhead[maxn];
    
    void init()//初始化 
    {
        memset(vis,0,sizeof(vis));
        memset(head,-1,sizeof(head));
        memset(stack,0,sizeof(stack));
        memset(dfn,0,sizeof(dfn));
        memset(f,0,sizeof(f));
        memset(newhead,-1,sizeof(newhead));
        top=cnt=scs=num=0;
    }
    
    void add(int u,int v)//城市和城市相连 
    {
        edge[cnt].v=v;
        edge[cnt].nxt=head[u];
        head[u]=cnt++;
    }
    
    void add1(int u,int v)//强联通分量相连 
    {
        e[cnt].v=v;
        e[cnt].nxt=newhead[u];
        newhead[u]=cnt++;
    }
    void tarjan(int u)//tarjan算出强连通分量,并缩点(将同一强连通分量的城市看作一个点) 
    {
        low[u]=dfn[u]=++scs;
        stack[top++]=u;
        vis[u]=1;
        for(int i=head[u];i!=-1;i=edge[i].nxt)
        {
            int v=edge[i].v;
            if(!dfn[v])
            {
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(vis[v])
                low[u]=min(low[u],dfn[v]);
        }
        if(low[u]==dfn[u])
        {
            int t;
            num++;
            do
            {
                t=stack[--top];
                vis[t]=0;
                rt[t]=num;//缩点,强连通分量编号
            }while(t!=u);
        }
    }
    
    bool find(int x)//匈牙利算法中的是否可以匹配,让位置 
    {
        for(int i=newhead[x];i!=-1;i=e[i].nxt)
        {
            int v=e[i].v;
            if(!used[v])
            {
                used[v]=1;
                if(f[v]==0||find(f[v]))
                {
                    f[v]=x;
                    return true;
                }
            }
        }
        return false;
    }
    
    int main()
    {
        int t,n,m,ans;
        cin>>t;
        while(t--)
        {
            init();
            cin>>n>>m;
            for(int i=0;i<m;i++)
            {
                cin>>x[i]>>y[i];
                add(x[i],y[i]);
            }
            for(int i=1;i<=n;i++)
                if(!dfn[i])
                    tarjan(i);
            cnt=0;
            for(int i=0;i<m;i++)//强连通分量相连 
            {
                int xx=rt[x[i]],yy=rt[y[i]];
                if(xx!=yy)//强连通分量不同 ,由于城市相连,所以 强连通分量相连可能划为一个州
                    add1(xx,yy);    
            }
            ans=0;
            for(int i=1;i<=num;i++)//二分图最大匹配 
            {
                memset(used,0,sizeof(used));
                if(find(i))
                    ans++;//最大匹配数 
            }
            //cout<<num<<" "<<ans<<endl;
            cout<<num-ans<<endl;
        }
        return 0;
    }
  • 相关阅读:
    移动视频开发让我们把会议室装进口袋里
    音视频 开发技术,让智能家居更智能!
    视频对讲SDK 大厅好友解决方案
    视频开发的安全保障措施
    手机视频开发即时通讯软件
    借音视频开发技术,开发招聘新途径
    移动视频技术的先驱
    tf.variable_scope
    sklearn 数据预处理
    Tensorflow自编码器及多层感知机
  • 原文地址:https://www.cnblogs.com/xiongtao/p/9385733.html
Copyright © 2011-2022 走看看