• HDU 3861 The King’s Problem (强连通缩点+DAG最小路径覆盖)


    <题目链接>

    题目大意:

    一个有向图,让你按规则划分区域,要求划分的区域数最少。

    规则如下:1.所有点只能属于一块区域;2,如果两点相互可达,则这两点必然要属于同一区域;3,区域内任意两点至少有一方能够到达另一方。

    解题分析:

    双连通的两点必须要属于一块区域,所以可以直接对相互连通的点进行缩点,然后再分析缩点后的图像,因为题目要求划分的区域最少,且区域内的"点"之间至少有一方能够到达另一方。仔细思考后,发现就是对缩点后的图求最小路径覆盖。区域内的"点"至少要有一方能够到达另一方,所以"点"之间连接的道路就可以看成他们之间的匹配关系。图的最小路径覆盖=总点数-最大匹配数。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <vector>
     4 #include <algorithm>
     5 #include <cstring>
     6 using namespace std;
     7 
     8 #define clr(a,b) memset(a,b,sizeof(a))
     9 #define rep(i,s,t) for(int i=s;i<=t;i++)
    10 #define pb push_back
    11 const int N = 5e3+10;
    12 int  dfn[N], low[N], stk[N], belong[N], vis[N], match[N];
    13 bool instk[N];
    14 int top, scc, tot, n, m, T;
    15 vector<int>vt[N],G[N];
    16 
    17 void init(){
    18     top=scc=tot=0;
    19     clr(dfn,0);clr(low,0);clr(instk,false);
    20 }
    21 void Tarjan(int u){       //tarjan进行缩点
    22     dfn[u]=low[u]=++tot;
    23     stk[++top]=u;instk[u]=1;
    24     for(int i=0; i<vt[u].size(); i++){
    25         int v=vt[u][i];
    26         if(!dfn[v]){
    27             Tarjan(v);
    28             low[u]=min(low[u],low[v]);
    29         }else if(instk[v])
    30             low[u]=min(low[u],dfn[v]);
    31     }
    32     if(low[u]==dfn[u]){
    33         scc++;
    34         while(true){
    35             int v=stk[top--];
    36             instk[v]=0;
    37             belong[v]=scc;
    38             if(v==u)break;
    39         }
    40     }
    41 }
    42 bool dfs(int u){    
    43     for(int i=0; i<G[u].size(); i++){
    44         int v=G[u][i];
    45         if(!vis[v]){
    46             vis[v]=1;
    47             if(match[v]==-1||dfs(match[v])){
    48                 match[v]=u;
    49                 return true;
    50             }
    51         }
    52     }
    53     return false;
    54 }
    55 int Hungary(){    //匈牙利匹配,对缩点后的"点"求最大匹配
    56     int res=0;
    57     clr(match,-1);
    58     rep(i,1,scc){
    59         clr(vis,0);
    60         if(dfs(i))res++;
    61     }
    62     return res;
    63 }
    64 int main(){
    65     scanf("%d",&T);while(T--){
    66         scanf("%d%d",&n,&m);
    67         for(int i=0; i<=n; i++) vt[i].clear();
    68         rep(i,1,m){
    69             int u,v;scanf("%d%d",&u,&v);
    70             vt[u].pb(v);
    71         }
    72         init();
    73         rep(i,1,n)
    74             if(!dfn[i]) Tarjan(i);     //对所有双连通的点进行缩点
    75         rep(i,0,n)G[i].clear();
    76         rep(u,1,n) for(int i=0;i<vt[u].size();i++){
    77             int v=vt[u][i];
    78             if(belong[u]!=belong[v])
    79                 G[belong[u]].pb(belong[v]);   
    80         }
    81         int res=Hungary();
    82            printf("%d
    ",scc-res);    //求出缩点后的"点"的最小路径覆盖
    83     }
    84 }

    2018-11-27

  • 相关阅读:
    git add用法
    git删除指定文件夹
    git相关命令
    Stacktrace: org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:5
    [程序员代码面试指南]数组和矩阵-子矩阵的最大累加和问题
    [程序员代码面试指南]二叉树问题-统计完全二叉树的节点数
    [排序]直接插入排序、希尔排序
    [程序员代码面试指南]判断字符数组中是否所有字符只出现一次(堆排序)
    [SpringBoot项目]笔记
    [计算机网络]知识点
  • 原文地址:https://www.cnblogs.com/00isok/p/10029254.html
Copyright © 2020-2023  润新知