HDU 3861 The King’s Problem(tarjan连通图与二分图最小路径覆盖)
题意:给我们一个图,问我们最少能把这个图分成几部分,使得每部分内的任意两点都能至少保证单向连通。
思路:使用tarjan算法求强连通分量然后进行缩点,形成一个新图,易知新图中的每个点内部的内部点都能保证双向连通,而新图中的点都是单向无环的,这个时候题目中要求的划分部分的条件,其实就是求最短路径覆盖(需要好好想一想),最短路径覆盖 = 结点个数 - 最大匹配值。
这个题我当时把j写成了i,就这么一个小地方,找了快20分钟,还死活发现不了。。真是晕死了~
最后我想总结一下这个题:
这个题很巧妙的把割点和二分图巧妙的结合了在一起,最后变成了最小路径覆盖问题,我就把我对最短路径覆盖的理解说一下吧:
最短路径覆盖,针对有向图而言,是找到最少的路径使覆盖所有的点,每个点的入度与出度最多是1,他的计算方法是 最短路径覆盖 = 结点个数 - 最大匹配值。
证明: 如果有n个点,0个匹配,那我们就有n条路径(一个单独的点也要被看作一条路径),当我们找到一个u和v的匹配的时候,我们需要的路径就少一,以此类推,就证明出了以上结论。
我在观察匹配算法的深搜树的时候发现了,我并没有去按照分两边集合的方式去考虑,而是按照父亲优先让出的原则去思考的,这个想法基于每个点只能最多有一个入度和出度,而且在深搜的过程中,每次直接匹配或迭代匹配都会使结果加1,但是迭代匹配有可能进行进行多次,但结果只加了1,其实是后来在的遍历中计算了结果,这也是为什么vis数组必须清空的原因之一。在匹配过程中我们并不关心匹配的方案,只关心匹配的最大数值,同一个值有可能对应多条匹配方案是当然的,但在二分图的题目中,很少有要求输出方案的,有的话也是随便输出一条,那直接输出我们随机匹配的match就好了~(仅代表个人看法)。
#include<iostream>
#include<cstdio>
#include<stack>
#include<cstring>
using namespace std;
#define maxn 5050
struct EDGE
{
int to,nxt;
} edge[maxn*];
EDGE newmap[maxn*];
int head[maxn],low[maxn],dfn[maxn],id[maxn],newhead[maxn];
int vis[maxn],match[maxn];
int tot,sum,tot1;
stack <int> s;
void init()
{
memset(dfn,,sizeof(dfn));
memset(low,,sizeof(low));
memset(id,,sizeof(id));
memset(head,-,sizeof(head));
memset(newhead,-,sizeof(newhead));
tot = ,sum = ;
tot1 = ;
while(!s.empty()) s.pop();
}
void add_edge(int x,int y)
{
newmap[tot1].to = y;
newmap[tot1].nxt = newhead[x];
newhead[x] = tot1++;
}
void tarjan(int u)
{
s.push(u);
dfn[u] = low[u] = ++tot;
for(int i = head[u]; i != -; i = edge[i].nxt)
{
int v = edge[i].to;
if(!dfn[v])
{
tarjan(v);
low[u] = min(low[u],low[v]);
}
else if(!id[v])
{
low[u] = min(low[u],dfn[v]);
}
}
if(low[u] == dfn[u])
{
sum++;
while(!s.empty())
{
int num = s.top();
s.pop();
id[num] = sum;
if(num == u) break;
}
}
return;
}
bool Find(int u)
{
for(int i = newhead[u]; i != -;i = newmap[i].nxt)
{
int v = newmap[i].to;
if(!vis[v])
{
vis[v] = ;
if(match[v] == - || Find(match[v]))
{
match[v] = u;
return true;
}
}
}
return false;
}
int erfen()
{
int ans = ;
memset(match,-,sizeof(match));
for(int i = ;i <= sum;i++)
{
for(int j = ;j <= sum;j++) vis[j] = ;
if(Find(i)) ans++;
}
return ans;
}
int main()
{
int t,n,m,x,y;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
init();
for(int i = ; i < m; i++)
{
scanf("%d%d",&x,&y);
edge[i].to = y;
edge[i].nxt = head[x];
head[x] = i;
}
for(int i = ;i <= n;i++)
{
if(!dfn[i])
tarjan(i);
}
for(int i = ;i <= n;i++)
{
int u = i;
for(int j = head[u];j != -;j = edge[j].nxt)
{
int v = edge[j].to;
if(id[u] != id[v])
{
add_edge(id[u],id[v]);
}
}
}
int ans = erfen();
printf("%d\n",sum-ans);
}
return ;
}
HDU 3861 The King’s Problem(tarjan连通图与二分图最小路径覆盖)的更多相关文章
- HDU 3861 The King’s Problem (强连通缩点+DAG最小路径覆盖)
<题目链接> 题目大意: 一个有向图,让你按规则划分区域,要求划分的区域数最少. 规则如下:1.所有点只能属于一块区域:2,如果两点相互可达,则这两点必然要属于同一区域:3,区域内任意两点 ...
- 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 ...
- hdu3861 The King’s Problem 强连通缩点+DAG最小路径覆盖
对多校赛的题目,我深感无力.题目看不懂,英语是能懂的,题目具体的要求以及需要怎么做没有头绪.样例怎么来的都不明白.好吧,看题解吧. http://www.cnblogs.com/kane0526/ar ...
- HDU 3861 The King’s Problem(强连通+二分图最小路径覆盖)
HDU 3861 The King's Problem 题目链接 题意:给定一个有向图,求最少划分成几个部分满足以下条件 互相可达的点必须分到一个集合 一个对点(u, v)必须至少有u可达v或者v可达 ...
- HDU 3861.The King’s Problem 强联通分量+最小路径覆盖
The King’s Problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- HDU 3861 The King’s Problem 最小路径覆盖(强连通分量缩点+二分图最大匹配)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3861 最小路径覆盖的一篇博客:https://blog.csdn.net/qq_39627843/ar ...
- HDU 3861 The King’s Problem(强连通分量+最小路径覆盖)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3861 题目大意: 在csdn王国里面, 国王有一个新的问题. 这里有N个城市M条单行路,为了让他的王国 ...
- hdu——3861 The King’s Problem
The King’s Problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- HDU 3861 The King's Problem(强连通分量缩点+最小路径覆盖)
http://acm.hdu.edu.cn/showproblem.php?pid=3861 题意: 国王要对n个城市进行规划,将这些城市分成若干个城市,强连通的城市必须处于一个州,另外一个州内的任意 ...
随机推荐
- C/C++ - <string> 与<string.h>、<cstring>的区别
<string.h><string.h>是C版本的头文件,包含比如strcpy.strcat之类的字符串处理函数. <string><string>是C ...
- [kuangbin带你飞]专题四 最短路练习 POJ 2253 Frogger
求第一个点到第二个点的所有通路上最长的边 dijkstra的变形 每次松弛的是每条边通路上的的最长的边 WA了好几次是因为用了%lf 改成%f就过了…… /* ******************** ...
- LoadLibrary 失败 GetLastError 126
这个错误可能是 Load的库依赖另外的库,而其依赖的库不存在,也会返回这个错误!
- Openjudge-计算概论(A)-分数求和
描述: 输入n个分数并对他们求和,并用最简形式表示.所谓最简形式是指:分子分母的最大公约数为1:若最终结果的分母为1,则直接用整数表示. 如:5/6.10/3均是最简形式,而3/6需要化简为1/2, ...
- 【Loadrunner】初学Loadrunner——安装
一.准备工作 1.下载Loadrunner可以参考网上百度得到的可以在下面这个地址下载,比较大,4G左右 http://www.genilogix.com/downloads/loadrunner/l ...
- vmware虚拟机如何安装ubuntu14.10系统
vmware虚拟机安装ubuntu14.10系统安装步骤如下:
- oracle 导入sql中文乱码(转)
导入sql的有中文,直接在linux环境下进行复制粘贴的,发现进去的都是乱码, 修改如下: 进入oracle用户,#vi /home/oracle/.bash_profile; 在最后一行添加:exp ...
- Oracle SQL 内置函数大全
SQL中的单记录函数 1.ASCII 返回与指定的字符对应的十进制数;SQL> select ascii('A') A,ascii('a') a,ascii('0') zero,ascii(' ...
- sort 排序详解
http://www.qdfuns.com/notes/17398/c56832f62b3271e79671f77dcdd2c058.html. http://www.qdfuns.com/notes ...
- java计数器CountDownLatch
CountDownLatch里面有个属性为state,当为零时触发代码往下执行,代码如下: package threadLock; import java.util.Random; import ja ...