POJ 2594 最小路径覆盖问题
最小路径覆盖定义是在有向图上选最少的路径经过有向图的每一个点, 且每个点只与一条路径相关。 相当于最少个数的人无重复的走完全图
最小路径覆盖 = 顶点数 - 匹配数
证明如下:
1,:图中没有边的时候显然成立
2.图中有边的时候匹配数每增加1, 那么需要的人数就减1
这道题也是让最少的人走完全部的图, 不同的是允许不同的人走一样的点, 我们可以通过传递闭包处理下将问题转化为上述问题。代码如下:
#include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int maxn = 1000+100; int V; //定点数 vector<int> G[maxn]; int match[maxn]; bool used[maxn]; void init() { for(int i=0; i<=V; i++) G[i].clear(); } void add_edge(int u, int v) { G[u].push_back(v); G[v].push_back(u); } bool dfs(int u){ used[u] = true; for(int i=0; i<G[u].size(); i++){ int v = G[u][i], w = match[v]; if(w<0 || (!used[w]&&dfs(w))){ match[u] = v; match[v] = u; return true; } } return false; } int hun(){ int res = 0; memset(match, -1, sizeof(match)); for(int u=0; u<V; u++){ if(match[u] < 0){ memset(used, 0, sizeof(used)); if(dfs(u)) res++; } } return res; } int N, M; int d[550][550]; int main() { while(scanf("%d%d", &N, &M) == 2){ if(N==0 && M==0) break; //0 - N-1 N - 2*N-1 V = 2*N; init(); memset(d, 0, sizeof(d)); for(int i=0; i<M; i++){ int u, v; scanf("%d%d", &u, &v); d[u-1][v-1] = 1; } for(int k=0; k<N; k++) for(int i=0; i<N; i++) for(int j=0; j<N; j++) d[i][j] = d[i][j]||(d[i][k]&&d[k][j]); for(int u=0; u<N; u++) for(int v=0; v<N; v++) if(d[u][v]) G[u].push_back(N+v); printf("%d\n", N-hun()); } return 0; }