zoukankan      html  css  js  c++  java
  • hdu3861 The King’s Problem (强连通+最小路径覆盖)

    题意:题目的意思很清晰,对于一个有向图,将N个点划分成最少的集合个数,同时满足俩个条件:

    1) 任意俩点,若互相可达,则必须在同一个集合中

    2)属于同一个集合的任意俩个点对(u,v),至少存在一条路径,使得v对于u 可达 或者 u 对于v 可达

    分析:对于上述俩个条件,为了简化问题,需要进行缩点,属于同一个强连通分量的点,缩成同一个点,重新构图,可以用tarjan 算法;

    这样,第一个条件就一定满足了,接着只剩下第二个条件了,其实,任意俩点,只要在同一条有向路径上,则可以属于一个集合,,,那么问题就转化为用最小的有向路径去覆盖所有的点(最小路径覆盖数==点数-最大匹配数)

    View Code
    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<stack>
    using namespace std;
    const int N = 5000+10;
    vector<int> g[N],g2[N];
    stack<int> st; 
    int n,dfn[N],low[N],f[N],index; 
    int num,match[N]; 
    bool vis[N],instack[N]; 
    void tarjan(int u)//求强连通分支
    { 
        int v; 
        dfn[u] = low[u] = index++;  
        st.push(u);   
        instack[u] = true; 
        vis[u] = true; 
        for(int i=0; i<g[u].size(); i++) 
        {     
            v = g[u][i];       
            if(!vis[v]) 
            {               
                tarjan(v);       
                low[u] = min(low[u], low[v]);  
            }          
            else if(instack[v]) 
                low[u] = min(low[u], dfn[v]); 
        }    
        if(dfn[u] == low[u]) 
        {             
            do 
            {           
                v = st.top();             
                instack[v] = false; 
                st.pop();         
                f[v]=num;//记录每一个点所在的强连通分支   
            } 
            while(v != u); 
            num++;  
        }
    }
    int path(int s)
    {
        vector<int>::iterator it=g2[s].begin();
        for(;it!=g2[s].end();it++)
        {
            int v=*it;
            if(!vis[v])
            {
                vis[v]=true;
                if(match[v]==-1 || path(match[v]))
                {
                    match[v]=s;
                    return 1;
                }
            }
        }
        return 0;
    }
    int main()
    {
        int T,cas=0,m,a,b;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d %d",&n,&m);
            for(int i=0;i<=n;i++) 
            {
                g[i].clear();
                g2[i].clear();
            }
            while(m--) 
            {
                scanf("%d %d",&a,&b); 
                g[a].push_back(b);
            }
            memset(vis,false,sizeof(vis)); 
            memset(instack,false,sizeof(instack)); 
            index=num=0; 
            for(int i=1;i<=n;i++) 
            {
                if(!vis[i]) 
                    tarjan(i);
            }
            for(int i=1;i<=n;i++) //重新构图
                for(int j=0;j<g[i].size();j++) 
                {
                    if(f[i]!=f[g[i][j]]) 
                    {
                        g2[f[i]].push_back(f[g[i][j]]);
                    }
                }
            memset(match,-1,sizeof(match));
            int ans=0;
            for(int i=0;i<num;i++)//求最大匹配数
            {
                memset(vis,false,sizeof(vis));
                ans+=path(i);
            }
            printf("%d\n",num-ans);
        }
        return 0;
    }
  • 相关阅读:
    Turtlebot3 OpenCR 机器人端刷固件方案(包括ROS1和ROS2)
    TurtleBot3自动驾驶Noetic模拟仿真项目 1.准备工作
    OpenManipulatorX Gazebo仿真(Noetic)
    Ned
    OpenMANIPULATORX Melodic ROS包安装
    TurtleBot3自动驾驶Noetic6.模拟隧道
    Turtlebot3 Noetic ROS包安装
    WEB网站发布服务器IIS报错问题终极解决方案,查到问题点
    理解javascript中的连续赋值
    C# webBrowser.DocumentCompleted 解决之道
  • 原文地址:https://www.cnblogs.com/nanke/p/2509173.html
Copyright © 2011-2022 走看看