POJ 1422 Air Raid

开始以为是求最小支配集,结果给我胡乱AC了。后来感觉不太对,去搜解题报告才知道是最小路径覆盖。

【建模分析】
对于一个路径覆盖,有如下性质:
1、每个顶点属于且只属于一个路径。
2、路径上除终点外,从每个顶点出发只有一条边指向路径上的另一顶点。
所以我们可以把每个顶点理解成两个顶点,一个是出发,一个是目标,建立二分图模型。该二分图的任何一个匹配方案,都对应了一个路径覆盖方案。如果匹配数为0,那么显然路径数=顶点数。每增加一条匹配边,那么路径覆盖数就减少一个,所以路径数=顶点数 – 匹配数。要想使路径数最少,则应最大化匹配数,所以要求二分图的最大匹配。
注意,此建模方法求最小路径覆盖仅适用于有向无环图,如果有环或是无向图,那么有可能求出的一些环覆盖,而不是路径覆盖。

推荐一个不错的博客:

http://www.byvoid.com/blog/lpf24-3/

CODE:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib> 
using namespace std;

#define MAXN 130
#define MAXM 20010

int G[MAXN][MAXN];

int xlink[MAXN];
int ylink[MAXN];
bool vis[MAXN];  

int nx, ny, m;

inline void init()
{
	memset(G, 0, sizeof(G));
	memset(xlink, -1, sizeof(xlink));
	memset(ylink, -1, sizeof(ylink));
}

bool ED(int u)
{
	for(int v = 1; v <= ny; v++) if(G[u][v]) 
	{
		if(!vis[v]) 
		{
			vis[v] = 1;
			if(ylink[v] == -1 || ED(ylink[v])) 
			{ 
				xlink[u] = v;
				ylink[v] = u; 
				return true;
			} 
		}
	}
	return false;
}

void MaxMatch()
{
	int ans = 0;
	for(int i = 1; i <= nx; i++)
	{
		if(xlink[i] == -1)
		{
			memset(vis, 0, sizeof(vis));
			ans += ED(i);
		}
	}
	printf("%d\n", nx-ans);
}

int main()
{
	int T;
	scanf("%d", &T);
	while(T--)
	{
		init();
		scanf("%d%d", &nx, &m);
		ny = nx;
		while(m--)
		{
			int u, v;
			scanf("%d%d", &u, &v);
			G[u][v] = 1;
		}
		MaxMatch();
	}
	return 0;
}


你可能感兴趣的:(POJ 1422 Air Raid)