题目链接: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进行缩点,然后,规则2,3就是求DAG(有向无环图)最小路径覆盖。(最小路径覆盖=顶点数-最大匹配)

首先我们需要了解到最小覆盖路径的定义:通俗点将,就是在一个有向图中,找出最少的路径,使得这些路径经过了所有的点。

最小路径覆盖分为最小不相交路径覆盖和最小可相交路径覆盖。

最小不相交路径覆盖:每一条路径经过的顶点各不相同。如图,其最小路径覆盖数为3。即1->3>4,2,5。

最小可相交路径覆盖:每一条路径经过的顶点可以相同。如果其最小路径覆盖数为2。即1->3->4,2->3>5。

特别的,每个点自己也可以称为是路径覆盖,只不过路径的长度是0。

DAG的最小不相交路径覆盖

算法:把原图的每个点V拆成VxVx和VyVy两个点,如果有一条有向边A->B,那么就加边Ax−>ByAx−>By。这样就得到了一个二分图。那么最小路径覆盖=原图的结点数-新图的最大匹配数。

证明:一开始每个点都是独立的为一条路径,总共有n条不相交路径。我们每次在二分图里找一条匹配边就相当于把两条路径合成了一条路径,也就相当于路径数减少了1。所以找到了几条匹配边,路径数就减少了多少。所以有最小路径覆盖=原图的结点数-新图的最大匹配数。

因为路径之间不能有公共点,所以加的边之间也不能有公共点,这就是匹配的定义。

说的拆点这么高深,其实操作起来超级超级简单,甚至没有操作。

简单的来说,每个顶点都能当成二分图中作为起点的顶点。

至于为什么答案是 n-ans,我谈谈我的理解

用dfs求的ans表示的意思是匹配数,换句话说,就是一条路连着的路径上的点的个数-1

DAG的最小可相交路径覆盖

算法:先用floyd求出原图的传递闭包,即如果a到b有路径,那么就加边a->b。然后就转化成了最小不相交路径覆盖问题。

证明:为了连通两个点,某条路径可能经过其它路径的中间点。比如1->3->4,2->4->5。但是如果两个点a和b是连通的,只不过中间需要经过其它的点,那么可以在这两个点之间加边,那么a就可以直达b,不必经过中点的,那么就转化成了最小不相交路径覆盖。

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<stack>
using namespace std; int head[5010], used[5010], head1[5010];
int dfn[5010], low[5010], vis[5010], color[5010];
int deep, cnt, cnt1, kinds_color, goal[5010];
stack<int>S; struct Edge
{
int to, next;
}edge[100010], edge1[100010]; void add(int a, int b) //存边
{
edge[++ cnt].to = b;
edge[cnt].next = head[a];
head[a] = cnt;
} void Add(int a, int b) //存缩点后的边
{
edge1[++ cnt1].to = b;
edge1[cnt1].next = head1[a];
head1[a] = cnt1;
} void tarjan(int now)
{
dfn[now] = low[now] = ++ deep;
S.push(now);
vis[now] = 1;
for(int i = head[now]; i != 0; i = edge[i].next)
{
int to = edge[i].to;
if(!dfn[to])
{
tarjan(to);
low[now] = min(low[now], low[to]);
}
else if(vis[to])
low[now] = min(low[now], dfn[to]);
}
if(low[now] == dfn[now])
{
kinds_color ++;
while(1)
{
int temp = S.top();
S.pop();
vis[temp] = 0;
color[temp] = kinds_color;
if(temp == now)
break;
}
}
} bool find(int x) //找最大匹配
{
for(int i = head1[x]; i !=0; i = edge1[i].next)
{
int t = edge1[i].to;
if(!used[t])
{
used[t] = 1;
if(!goal[t] || find(goal[t]))
{
goal[t] = x;
return true;
}
}
}
return false;
} int main()
{
int T, n, m;
int a, b, ans;
scanf("%d", &T);
while(T --)
{
deep = cnt = kinds_color = cnt1 = ans = 0;
memset(vis, 0, sizeof(vis));
memset(dfn, 0, sizeof(dfn));
memset(goal, 0, sizeof(goal));
memset(low, 0, sizeof(low));
memset(head, 0, sizeof(head));
memset(head1, 0, sizeof(head1));
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i ++)
{
scanf("%d%d", &a, &b);
add(a, b);
}
for(int i = 1; i <= n; i ++)
{
if(!dfn[i])
tarjan(i);
}
for(int i = 1; i <= n; i ++)
{
for(int j = head[i]; j != 0; j = edge[j].next)
{
int to = edge[j].to;
int x = color[i], y = color[to];
if(x != y)
Add(x, y);
}
}
for(int i = 1; i <= kinds_color; i ++)
{
memset(used, 0 ,sizeof(used));
if(find(i))
ans ++;
}
printf("%d\n", kinds_color - ans);
}
return 0;
}

  

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

  1. [luoguP2764] 最小路径覆盖问题(最大流 || 二分图最大匹配)

    传送门 可惜洛谷上没有special judge,不然用匈牙利也可以过的,因为匈牙利在增广上有一个顺序问题,所以没有special judge就过不了了. 好在这个题的测试数据比较特殊,如果是网络流的 ...

  2. HDU 3861 The King’s Problem(强连通+二分图最小路径覆盖)

    HDU 3861 The King's Problem 题目链接 题意:给定一个有向图,求最少划分成几个部分满足以下条件 互相可达的点必须分到一个集合 一个对点(u, v)必须至少有u可达v或者v可达 ...

  3. HDU 3861.The King’s Problem 强联通分量+最小路径覆盖

    The King’s Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

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

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3861 题目大意: 在csdn王国里面, 国王有一个新的问题. 这里有N个城市M条单行路,为了让他的王国 ...

  5. HDU 3861 The King's Problem(强连通分量缩点+最小路径覆盖)

    http://acm.hdu.edu.cn/showproblem.php?pid=3861 题意: 国王要对n个城市进行规划,将这些城市分成若干个城市,强连通的城市必须处于一个州,另外一个州内的任意 ...

  6. HDU 3861 The King’s Problem(tarjan连通图与二分图最小路径覆盖)

    题意:给我们一个图,问我们最少能把这个图分成几部分,使得每部分内的任意两点都能至少保证单向连通. 思路:使用tarjan算法求强连通分量然后进行缩点,形成一个新图,易知新图中的每个点内部的内部点都能保 ...

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

    <题目链接> 题目大意: 一个有向图,让你按规则划分区域,要求划分的区域数最少. 规则如下:1.所有点只能属于一块区域:2,如果两点相互可达,则这两点必然要属于同一区域:3,区域内任意两点 ...

  8. HDU 3861 The King’s Problem 强连通分量 最小路径覆盖

    先找出强连通分量缩点,然后就是最小路径覆盖. 构造一个二分图,把每个点\(i\)拆成两个点\(X_i,Y_i\). 对于原图中的边\(u \to v\),在二分图添加一条边\(X_u \to Y_v\ ...

  9. hdu 3861 The King’s Problem trajan缩点+二分图匹配

    The King’s Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

随机推荐

  1. JS高德地图计算两地之间的实际距离

    这个是通过导航的方式来获取两地之间的实际距离,和消耗的时间(key值自己去申请哈) <!doctype html> <html> <head> <meta c ...

  2. js定义数组集合

    简单描述:最近脑子有点抽,js要用到数组,竟然傻傻的写了 var [] str = .简直是糟糕的不要不要的 //js代码var str = [];var str =new Array(); 啥也不说 ...

  3. SpringBoot 集成数据库连接池Druid

    1.pom.xml依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>druid< ...

  4. php 文件系统函数及目录函数

    1.basename ,dirname ,pathinfo和realpath basename(path) 返回路径中的文件名部份,包含扩展名,path表示路径: dirname(path) 返回路径 ...

  5. thread - 传递引用参数

    当给 thread 的执行函数传递指针参数时,没有任何问题,但是如果想传递引用,按照普通函数的调用方法会遇到编译失败: #include <iostream> #include <t ...

  6. Linux中常用操作命令(转)

    1.cd命令 这是一个非常基本,也是大家经常需要使用的命令,它用于切换当前目录,它的参数是要切换到的目录的路径,可以是绝对路径,也可以是相对路径.如:   cd /root/Docements # 切 ...

  7. 集群环境下的Session共享

    一.Cookie机制和Session机制回顾 1)定义:Session成为“会话”,具体是指一个终端用户与交互系统进行通信的时间间隔,通常指从注册进入系统到注销退出系统之间所经过的时间.Session ...

  8. line-height:1.5和line-height:150%的区别

    1. 给你个数,孩子自己算吧  line-height:1.5 父元素设置line-height:1.5会直接继承给子元素,子元素根据自己的font-size再去计算子元素自己的line-height ...

  9. django——web框架简介

    1.web应用 Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件. 应用程序有两种模式C/S.B/S.C/S是客户 ...

  10. Linux bash基础特性二

    shell脚本的组成部分 shebang 各种命令组合 编程变量种类 本地变量: 仅仅在当前的shell生效 环境变量: 在当前和子shell生效 局部变量: shell进程某代码片段 位置变量: $ ...