题目:http://www.lightoj.com/volume_showproblem.php?problem=1403
题意:有一个小镇有十字路口和街道,抽象成n个顶点和m条有向边,两个顶点之间只有一条边且图中无环。现在有一些伞兵降落在小镇的任意路口,他们可以沿着街道走下去,求要参观所有的十字路口需要最少的伞兵数量
思路:最小路径覆盖裸题,直接建图,然后有最小路径覆盖 = 节点数 - 最大匹配
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 1010;
struct edge
{
int to, next;
}g[N*N];
int head[N], match[N];
int nx, ny, cnt, cas = 0;
bool used[N];
void add_edge(int v, int u)
{
g[cnt].to = u, g[cnt].next = head[v], head[v] = cnt++;
}
bool dfs(int v)
{
for(int i = head[v]; i != -1; i = g[i].next)
{
int u = g[i].to;
if(! used[u])
{
used[u] = true;
if(match[u] == -1 || dfs(match[u]))
{
match[u] = v;
return true;
}
}
}
return false;
}
int hungary()
{
int res = 0;
memset(match, -1, sizeof match);
for(int i = 1; i <= nx; i++)
{
memset(used, 0, sizeof used);
if(dfs(i)) res++;
}
return res;
}
int main()
{
int t, n, m, a, b;
scanf("%d", &t);
while(t--)
{
cnt = 0;
memset(head, -1, sizeof head);
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i++)
{
scanf("%d%d", &a, &b);
add_edge(a, b);
}
nx = n, ny = m;
printf("Case %d: %d\n", ++cas, n - hungary());
}
return 0;
}