hihoCoder:1394 : 网络流四·最小路径覆盖
https://hihocoder.com/problemset/problem/1394
描述
国庆期间正是旅游和游玩的高峰期。
小Hi和小Ho的学习小组为了研究课题,决定趁此机会派出若干个调查团去沿途查看一下H市内各个景点的游客情况。
H市一共有N个旅游景点(编号1..N),由M条单向游览路线连接。在一个景点游览完后,可以顺着游览线路前往下一个景点。
为了避免游客重复游览同一个景点,游览线路保证是没有环路的。
每一个调查团可以从任意一个景点出发,沿着计划好的游览线路依次调查,到达终点后再返回。每个景点只会有一个调查团经过,不会重复调查。
举个例子:
上图中一共派出了3个调查团:
1. 蓝色:调查景点;2
2. 橙色:调查景点;1->3->4->6
3. 绿色:调查景点;5->7
当然对于这个图还有其他的规划方式,但是最少也需要3个调查团。
由于小组内的人数有限,所以大家希望调查团的数量尽可能少,同时也要将所有的景点都进行调查。
当然,如何规划调查团线路的任务落到了小Hi和小Ho的头上。
输入
第1行:2个整数N,M。1≤N≤500,0≤M≤20,000。
第2..M+1行:2个数字u,v,表示一条有向边(u,v)。保证不会出现重复的边,且不存在环。
输出
第1行:1个整数,表示最少需要的调查团数量。
样例输入
7 7
1 2
1 3
2 4
3 4
4 5
4 6
5 7
样例输出
3
匈牙利算法:
#include <stdio.h>
#include <string.h>
#define N 550
int e[N][N], book[N], pre[N];
int n, m;
int dfs(int u)
{
int v;
for (v = 1; v <= n; v++){
if (e[u][v] && book[v] == 0){
book[v] = 1;
if (pre[v] == 0 || dfs(pre[v])){
pre[v] = u;
return 1;
}
}
}
return 0;
}
int main()
{
int u, v, sum, i;
while (scanf("%d%d", &n, &m) != EOF) {
for (i = 0; i < m; i++) {
scanf("%d%d", &u, &v);
e[u][v] = 1;
}
sum = 0;
for (i = 1; i <= n; i++)
{
memset(book, 0, sizeof(book));
if (dfs(i))
sum++;
}
printf("%d\n", n - sum);
}
return 0;
}
EK算法:
#include <stdio.h>
#include <string.h>
#include <queue>
#include <algorithm>
#define N 1020
using namespace std;
int n, m, inf=0x7f7f7f;
int e[N][N], pre[N], flow[N];
int bfs(int s, int t)
{
int u, v;
queue<int>q;
flow[s] = inf;
q.push(s);
while (!q.empty()){
u = q.front();
q.pop();
if (u == t)
break;
for (v = 0; v <= 2 * n + 1; v++)
{
if (e[u][v] && pre[v] == -1 && v!=s)
{
q.push(v);
pre[v] = u;
flow[v] = min(flow[u], e[u][v]);
}
}
}
if (pre[t] == -1)
return -1;
return flow[t];
}
int EK(int s, int t)
{
int d, p, sum = 0;
while (1){
memset(pre, -1, sizeof(pre));
d = bfs(s, t);
if (d == -1)
return sum;
sum += d;
p = t;
while (p != s) {
e[pre[p]][p] -= d;
e[p][pre[p]] += d;
p = pre[p];
}
}
return sum;
}
int main()
{
int u, v, i;
while (scanf("%d%d", &n, &m) != EOF){
memset(e, 0, sizeof(e));
for (i = 0; i < m; i++){
scanf("%d%d", &u, &v);
e[u][v+n] = 1;
}
for (i = 1; i <= n; i++) {
e[0][i] = 1;
e[n + i][2 * n + 1] = 1;
}
printf("%d\n", n - EK(0, 2 * n + 1));
}
return 0;
}