网络流二十四题之P2764 最小路径覆盖问题
题目描述
给定有向图 G=(V,E)G=(V,E) 。设 PP 是 GG 的一个简单路(顶点不相交)的集合。如果 VV 中每个定点恰好在PP的一条路上,则称 PP 是 GG 的一个路径覆盖。PP中路径可以从 VV 的任何一个定点开始,长度也是任意的,特别地,可以为 00 。GG 的最小路径覆盖是 GG 所含路径条数最少的路径覆盖。设计一个有效算法求一个 GAP (有向无环图) GG 的最小路径覆盖。
提示:设 V=\{1,2,...,n\}V={1,2,...,n} ,构造网络 G_1=\{V_1,E_1\}G1={V1,E1} 如下:
V_1=\{x_0,x_1,...,x_n\}\cup\{y_0,y_1,...,y_n\}V1={x0,x1,...,xn}∪{y0,y1,...,yn}
E_1=\{(x_0,x_i):i\in V\}\cup\{(y_i,y_0):i\in V\}\cup\{(x_i,y_j):(i,j)\in E\}E1={(x0,xi):i∈V}∪{(yi,y0):i∈V}∪{(xi,yj):(i,j)∈E}
每条边的容量均为 11 ,求网络 G_1G1 的 (x_0,y_0)(x0,y0) 最大流。
输入输出格式
输入格式:
第一行有 22 个正整数 nn 和 mm 。 nn 是给定\text{GAP}GAP(有向无环图) GG 的顶点数, mm 是 GG 的边数。接下来的 mm行,每行有两个正整数 ii 和 jj 表示一条有向边 (i,j)(i,j)。
输出格式:
从第1 行开始,每行输出一条路径。文件的最后一行是最少路径数。
输入输出样例
11 12
1 2
1 3
1 4
2 5
3 6
4 7
5 8
6 9
7 10
8 11
9 11
10 11
1 4 7 10 11
2 5 8
3 6 9
3
说明
1\leq n\leq 150,1\leq m\leq 60001≤n≤150,1≤m≤6000
由@FlierKing提供SPJ
这个题目有点难读,我读了挺久的,这个题目是让你找最少的路径使得所有的路径合在一起可以覆盖了整个图。
没有最少自然可以是n,就是所有点自成一条路径。
拆分题目有点难写,我开始根本就没有什么思路,后来看到二分图匹配有一个关于这个的定理,
DAG图的最小路径覆盖数 = 节点数 - 二分图的最大匹配
所以这个就可以求解,然后这个转化成二分图,就需要把一个点拆成两个点,然后再合并。
说多了也没用,自己看代码理解吧。
我开始看题解,以为只能用链式前向星建图,真的要哭了,不太会用,后来发现也可以用vector
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <iostream>
#include <vector>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = ;
int level[maxn], iter[maxn];
int head[maxn];
int n,m,s = , t = ;
struct node
{
int to, cap,flow;
int nex;
}exa[maxn<<];
int cnt = ;
void add(int u,int v,int c)
{
exa[++cnt].to = v;
exa[cnt].cap = c;
exa[cnt].flow = ;
exa[cnt].nex = head[u];
head[u] = cnt;
//printf("%d %d %d %d %d\n",cnt,u, exa[cnt].to, exa[cnt].cap, exa[cnt].nex); exa[++cnt].to = u;
exa[cnt].cap = ;
exa[cnt].flow = ;
exa[cnt].nex = head[v];
head[v] = cnt;
//printf("%d %d %d %d %d\n",cnt,v, exa[cnt].to, exa[cnt].cap, exa[cnt].nex);
} void bfs(int s)
{
queue<int>que;
que.push(s);
memset(level, -, sizeof(level));
level[s] = ;
while(!que.empty())
{
int u = que.front(); que.pop();
//printf("%d %d %d\n", u,head[u],exa[head[u]].nex);
for(int i=head[u];i!=-;i=exa[i].nex)
{
node &now = exa[i];
//printf("%d %d %d\n", i, exa[i].to, exa[i].nex);
if(level[now.to]<&&now.cap>now.flow)
{
level[now.to] = level[u] + ;
que.push(now.to);
}
}
}
}
int tag[maxn], to[maxn]; int dfs(int u,int v,int f)
{
if (u == v) return f;
for(int &i=iter[u];i!=-;i=exa[i].nex)
{
node &now = exa[i];
if(now.cap>now.flow&&level[now.to]>level[u])
{
int d = dfs(now.to, v, min(f, now.cap - now.flow));
if(d>)
{
to[u] = now.to;
if (u != s) tag[now.to - n] = ;
now.flow += d;
exa[i ^ ].flow -= d;
return d;
}
}
}
return ;
}
void init()
{
memset(head, -, sizeof(head));
}
int dinic(int s,int t)
{
int flow = ;
while()
{
bfs(s);
if (level[t] < ) break;
for (int i = s; i <= t; i++) iter[i] = head[i];
int f;
while ((f = dfs(s, t, inf)) > ) flow += f; }
for(int i=;i<=n;i++)
{
if(!tag[i])
{
int now = i;
printf("%d ", now);
while(to[now]&&to[now]!=t)
{
printf("%d ", to[now] - n);
now = to[now] - n;
}
printf("\n");
}
}
return flow;
} int main()
{
init();
cin >> n >> m;
t = * n + ;
for (int i = ; i <= n; i++) add(s, i, );
for (int i = ; i <= n; i++) add(i+n, t, );
for(int i=;i<=m;i++)
{
int a, b;
cin >> a >> b;
add(a, b+n, );
}
int ans = dinic(s, t);
printf("%d\n",n - ans);
return ;
}
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <iostream>
#include <vector>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = ;
int level[maxn], iter[maxn];
int n,m,s = , t = ;
struct node
{
int from,to, cap,flow;
node(int from=,int to=,int cap=,int flow=):from(from),to(to),cap(cap),flow(flow){} };
vector<node>e;
vector<int>G[maxn];
void add(int u,int v,int c)
{
e.push_back(node(u, v, c, ));
e.push_back(node(v, u, , ));
int len = e.size();
G[u].push_back(len - );
G[v].push_back(len - );
} void bfs(int s)
{
queue<int>que;
que.push(s);
memset(level, -, sizeof(level));
level[s] = ;
while(!que.empty())
{
int u = que.front(); que.pop();
for(int i=;i<G[u].size();i++)
{
node &now = e[G[u][i]];
if(level[now.to]<&&now.cap>now.flow)
{
level[now.to] = level[u] + ;
que.push(now.to);
}
}
}
}
int tag[maxn], to[maxn]; int dfs(int u,int v,int f)
{
if (u == v) return f;
for(int &i=iter[u];i<G[u].size();i++)
{
node &now = e[G[u][i]];
if(now.cap>now.flow&&level[now.to]>level[u])
{
int d = dfs(now.to, v, min(f, now.cap - now.flow));
if(d>)
{
to[u] = now.to;
// printf("%d %d\n", u, to[u]);
if (u != s) tag[now.to - n] = ;
now.flow += d;
e[G[u][i] ^ ].flow -= d;
return d;
}
}
}
return ;
}
void init()
{
for (int i = ; i <= n + ; i++) G[i].clear();
e.clear();
}
int dinic(int s,int t)
{
int flow = ;
while()
{
bfs(s);
if (level[t] < ) break;
memset(iter, , sizeof(iter));
int f;
while ((f = dfs(s, t, inf)) > ) flow += f; }
//cout << endl;
for(int i=;i<=n;i++)
{
if(!tag[i])
{
int now = i;
printf("%d ", now);
while(to[now]&&to[now]!=t)
{
printf("%d ", to[now] - n);
now = to[now] - n;
}
printf("\n");
}
}
return flow;
} int main()
{
init();
cin >> n >> m;
t = * n + ;
for (int i = ; i <= n; i++) add(s, i, );
for (int i = ; i <= n; i++) add(i+n, t, );
for(int i=;i<=m;i++)
{
int a, b;
cin >> a >> b;
add(a, b+n, );
}
int ans = dinic(s, t);
printf("%d\n",n - ans);
return ;
}
网络流二十四题之P2764 最小路径覆盖问题的更多相关文章
- 网络流二十四题,题解summary
没有全部写完,有几题以后再补吧. 第一题:最简单的:飞行员配对方案问题 讲讲这个题目为什么可以用网络流? 因为这个题目是要进行两两之间的匹配,这个就可以想到用二分图匹配,二分图匹配又可以用网络流写. ...
- P4013 数字梯形问题 网络流二十四题
P4013 数字梯形问题 题目描述 给定一个由 nn 行数字组成的数字梯形如下图所示. 梯形的第一行有 m 个数字.从梯形的顶部的 m 个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形 ...
- P2765 魔术球问题 网络流二十四题重温
P2765 魔术球问题 知识点::最小点覆盖 这个题目要拆点,这个不是因为每一个球只能用一次,而是因为我们要求最小点覆盖,所以要拆点来写. 思路: 首先拆点,然后就是开始建边,因为建边的条件是要求他们 ...
- P2764 最小路径覆盖问题 网络流重温
P2764 最小路径覆盖问题 这个题目之前第一次做的时候感觉很难,现在好多了,主要是二分图定理不太记得了,二分图定理 知道这个之后就很好写了,首先我们对每一个点进行拆点,拆完点之后就是跑最大流,求出最 ...
- Luogu P2764 最小路径覆盖问题(二分图匹配)
P2764 最小路径覆盖问题 题面 题目描述 «问题描述: 给定有向图 \(G=(V,E)\) .设 \(P\) 是 \(G\) 的一个简单路(顶点不相交)的集合.如果 \(V\) 中每个顶点恰好在 ...
- 洛谷 P2764 最小路径覆盖问题 解题报告
P2764 最小路径覆盖问题 问题描述: 给定有向图\(G=(V,E)\).设\(P\) 是\(G\) 的一个简单路(顶点不相交)的集合.如果\(V\) 中每个顶点恰好在\(P\) 的一条路上,则称\ ...
- P2764 最小路径覆盖问题(网络流24题之一)
题目描述 «问题描述: 给定有向图G=(V,E).设P 是G 的一个简单路(顶点不相交)的集合.如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖.P 中路径可以从V 的任何一个顶点开 ...
- 【刷题】洛谷 P2764 最小路径覆盖问题
题目描述 «问题描述: 给定有向图G=(V,E).设P 是G 的一个简单路(顶点不相交)的集合.如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖.P 中路径可以从V 的任何一个顶点开 ...
- P2764 最小路径覆盖问题
题目描述 «问题描述: 给定有向图G=(V,E).设P 是G 的一个简单路(顶点不相交)的集合.如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖.P 中路径可以从V 的任何一个顶点开 ...
随机推荐
- linux文本处理三剑客的学习
linux下有三个文本处理的神器.分别是grep,sed,awk.功能都是比较强大的. grep帮助: http://my-study-grep.readthedocs.io/en/latest/ s ...
- 记录:C++类内存分布(虚继承与虚函数)
工具:VS2013 先说一下VS环境下查看类内存分布的方法: 先选择左侧的C/C++->命令行,然后在其他选项这里写上/d1 reportAllClassLayout,它可以看到所有相关类的内存 ...
- OpenCV在C#中应用—OpenCVSharp
1.什么是OpenCVSharp 之前一直是基于OpenCV开发视觉算法,但C++语言对于GUI的开发相对于C#来说确实很不方便,之前就了解到C#下使用OpenCV可以使用EmguCV,这段时间 ...
- response.redirect 与location.href 的区别
最近做项目时发现,先弹出提示框,再跳转页面 这样写:Jscript.Alert("你好,Hello!"); Response.Redirect("/index.aspx& ...
- Java开发笔记(五十二)对象的类型检查
前面介绍了类的多态性,来自于鸡类的实例chicken,既能用来表达公鸡实例,也能用来表达母鸡实例.可是这导致了一个问题,假如在call方法内部需要手工判断输入参数属于公鸡实例还是母鸡实例,那该如何是好 ...
- 左侧固定,右侧自适应的布局方式理解margin负值理论
一.浮动布局 1.先让固定宽度的div浮动!使其脱离文档流.2.margin-left的值等于固定div的宽度相等. .aside{ float: left; width: 200px; backgr ...
- 通过JavaScript调用SOAP终结点执行实体消息
关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复148或者20150813可方便获取本文,同时可以在第一时间得到我发布的最新的博文信息,follow me! 利用OData终结点可以方便的对 ...
- iOS----------取数据的两种取法
NSMutableArray * dataArray =[responseDictionary valueForKeyPath:@"data.list_dic.list"]; NS ...
- getDimension与getDimensionPixelOffset与getDimensionPixelSize的区别
getDimension() 返回float型px值 精确 getDimensionPixelOffset() 返回int型px值 ...
- Python 使用Python远程连接并操作InfluxDB数据库
使用Python远程连接并操作InfluxDB数据库 by:授客 QQ:1033553122 实践环境 Python 3.4.0 CentOS 6 64位(内核版本2.6.32-642.el6.x86 ...