hdu3861 强连通+最小路径覆盖

题意:有 n 个点,m 条边的有向图,需要将这些点分成多个块,要求:如果两点之间有路径能够互相到达,那么这两个点必须分在同一块;在同一块内的任意两点相互之间至少要有一条路径到达,即 u 到达 v 或 v 到达 u;每个点都只能存在于单独一个块内。问最少需要划分多少块。

首先,对于如果两点之间能够相互到达则必须在同一块,其实也就是在同一个强连通分量中的点必须在同一块中,所以首先就是强连通缩点。然后在同一块内的任意两点之间要有一条路,那么其实就是对于一块内的强连通分量,至少要有一条路径贯穿所有分量。而这一条路径上的所有强连通分量就可以构成同一块。那么其实我们就是需要找出最少的这样的路径将所有点全部覆盖一遍,就是做一遍最小路径覆盖。

最小路径覆盖数=点数-拆点后的最大匹配数。

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stack>
  4 #include<queue>
  5 using namespace std;
  6
  7 const int maxn=10005;
  8 const int maxm=2e5+5;
  9
 10 int head[2][maxn],point[2][maxm],nxt[2][maxm],size[2];
 11 int n,t,scccnt;
 12 int stx[maxn],low[maxn],scc[maxn];
 13 int vis[maxn],match[maxn];
 14 stack<int>S;
 15
 16 void init(){
 17     memset(head,-1,sizeof(head));
 18     size[0]=size[1]=0;
 19 }
 20
 21 void add(int a,int b,int c=0){
 22     point[c][size[c]]=b;
 23     nxt[c][size[c]]=head[c][a];
 24     head[c][a]=size[c]++;
 25 }
 26
 27 void dfs(int s){
 28     stx[s]=low[s]=++t;
 29     S.push(s);
 30     for(int i=head[0][s];~i;i=nxt[0][i]){
 31         int j=point[0][i];
 32         if(!stx[j]){
 33             dfs(j);
 34             low[s]=min(low[s],low[j]);
 35         }
 36         else if(!scc[j]){
 37             low[s]=min(low[s],stx[j]);
 38         }
 39     }
 40     if(low[s]==stx[s]){
 41         scccnt++;
 42         while(1){
 43             int u=S.top();S.pop();
 44             scc[u]=scccnt;
 45             if(s==u)break;
 46         }
 47     }
 48 }
 49
 50 void setscc(){
 51     memset(stx,0,sizeof(stx));
 52     memset(scc,0,sizeof(scc));
 53     t=scccnt=0;
 54     for(int i=1;i<=n;++i)if(!stx[i])dfs(i);
 55     for(int i=1;i<=n;++i){
 56         for(int j=head[0][i];~j;j=nxt[0][j]){
 57             int k=point[0][j];
 58             if(scc[i]!=scc[k]){
 59                 add(scc[i],scc[k]+scccnt,1);
 60             }
 61         }
 62     }
 63 }
 64
 65 int dfs1(int k){
 66     for(int i=head[1][k];~i;i=nxt[1][i]){
 67         if(!vis[point[1][i]]){
 68             int p=point[1][i];
 69             vis[p]=1;
 70             if(match[p]==-1||dfs1(match[p])){
 71                 match[p]=k;
 72                 return 1;
 73             }
 74         }
 75     }
 76     return 0;
 77 }
 78
 79
 80 int main(){
 81     int T;
 82     scanf("%d",&T);
 83     while(T--){
 84         int m;
 85         scanf("%d%d",&n,&m);
 86         init();
 87         while(m--){
 88             int a,b;
 89             scanf("%d%d",&a,&b);
 90             add(a,b);
 91         }
 92         setscc();
 93         int ans=0;
 94         memset(match,-1,sizeof(match));
 95         for(int i=1;i<=2*scccnt;++i){
 96             memset(vis,0,sizeof(vis));
 97             if(dfs1(i)==1)ans++;
 98         }
 99         printf("%d\n",scccnt-ans);
100     }
101     return 0;
102 }

时间: 2024-12-28 22:46:47

hdu3861 强连通+最小路径覆盖的相关文章

hdu 3861 The King’s Problem (强连通+最小路径覆盖)

The King's Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1637    Accepted Submission(s): 600 Problem Description In the Kingdom of Silence, the king has a new problem. There are N cit

HDU3861-The King’s Problem(有向图强连通缩点+最小路径覆盖)

题目链接 题意:题目大意:一个有向图,让你按规则划分区域,要求划分的区域数最少. 规则如下: 1.有边u到v以及有边v到u,则u,v必须划分到同一个区域内. 2.一个区域内的两点至少要有一方能到达另一方. 3.一个点只能划分到一个区域内. 思路:根据规则1可知必然要对强连通分量进行缩点,缩点后变成了一个弱连通图.根据规则2.3可知即是要求图的最小路径覆盖. 代码: #include <iostream> #include <cstdio> #include <cstring&

HDU - 3861 The King’s Problem (强连通分量+最小路径覆盖)

思路:tarjarn缩点,然后剩下的就是纯粹的最小路径覆盖,最小路径覆盖=顶点数-匹配数.匹配数跑一遍匈牙利即可. 1 #include <iostream> 2 #include <queue> 3 #include <stack> 4 #include <cstdio> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <bitset

HDU - 3861 The King’s Problem(强连通分量+最小路径覆盖)

题目大意:给出一张有向图,要求你将这些点进行划分,划分依据如下 1.如果两个点互相可达,那么这两个点必须在一个集合中 2.同一个集合中任意两个点u,v要满足,要么u能到达v,要么v能到达u 3.一个点只能被划分到一个集合 问最少能划分成几个点集 解题思路:首先先求出所有的强连通分量,满足条件1 满足条件2,3的话,就要求出最小路径覆盖 所以可以将所有的强连通分量进行缩点,桥作为连接,然后匈牙利一下,求出最大匹配数,再用强连通分量的数量-最大匹配数,就是答案了 #include <cstdio>

hdu3861The King’s Problem (强连通 缩点+最小路径覆盖)

The King's Problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1606 Accepted Submission(s): 584 Problem Description In the Kingdom of Silence, the king has a new problem. There are N cities in

Light OJ 1406 Assassin`s Creed 状态压缩DP+强连通缩点+最小路径覆盖

题目来源:Light OJ 1406 Assassin`s Creed 题意:有向图 派出最少的人经过全部的城市 而且每一个人不能走别人走过的地方 思路:最少的的人能够走全然图 明显是最小路径覆盖问题 这里可能有环 所以要缩点 可是看例子又发现 一个强连通分量可能要拆分 n最大才15 所以就状态压缩 将全图分成一个个子状态 每一个子状态缩点 求最小路径覆盖 这样就攻克了一个强连通分量拆分的问题 最后状态压缩DP求解最优值 #include <cstdio> #include <cstri

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

The King's Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 2085    Accepted Submission(s): 741 Problem Description In the Kingdom of Silence, the king has a new problem. There are N cit

HDU 3861 The King&#39;s Problem(强连通分量缩点+最小路径覆盖)

http://acm.hdu.edu.cn/showproblem.php?pid=3861 题意: 国王要对n个城市进行规划,将这些城市分成若干个城市,强连通的城市必须处于一个州,另外一个州内的任意两个城市u,v,有从u到v的路径或从v到u的路径.求最少可以分成几个州. 思路: 这道题目挺好. 首先,强连通分量进行缩点,重新建图. 新建的图就是一个DAG图,接下来就转换成了最小路径覆盖问题. 最小路径覆盖就是用尽量少的不相交的简单路径覆盖DAG的所有顶点.每个顶点只属于一条路径,单个顶点也可以

HDU 3861 The King’s Problem 最小路径覆盖(强连通分量缩点+二分图最大匹配)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3861 最小路径覆盖的一篇博客:https://blog.csdn.net/qq_39627843/article/details/82012572 题意: 把城市至少分成几个块,规则有三 1. A能B,B能到A,那么A,B一定要在一起. 2. 一个城市只能属于一个块. (说明了是最小不相交覆盖)3. 在一个块里的城市,任意2点之间必须有路径. 对于规则1,就是说强连通的必须在一起,所以用Tarjan