题意:
N * M的矩阵,*代表城市, o代表空地,有四种信号覆盖设备,每种类型信号设备可以覆盖相临得一个点。问要把所有城市覆盖所需最少得设备数?
算法:
1.构图
关键是怎么构图,如果像poj3041那样以X,Y轴行列号为两个不同得集合,明显行不同,看下答案输出那么大就知道,于是我猜想是否可以用城市构图,
给城市标号,并且把标号分拆为2个点(vi,vi'), vi为X集合,vi'为Y集合。。然后我发现求出来得二分匹配答案很大,明显又不对。。
而且这里应该是用最少的边覆盖所有点。。。当时不知到有最小路径公式,看了解体报告才知道。发现自己瞎猜得建图正确了。
无向图最小路径 = N - 最大匹配 / 2
证明 http://baike.baidu.com/view/2444809.htm
2.直接用匈牙利算法求出答案
3.总结
要多看下二分图得概念,不能有知识盲点,了解各公式的证明。
自己应该思考更长时间,或许可以YY出公式,因为只要想到增加一条匹配边,那么所需要的设备数肯定少1,
也就是匹配数目与设备数目是相反的,一个递增,另一个就递减。
View Code
//无向图最小路径覆盖 #include<stdio.h> #include<string.h> #include<stdlib.h> #include<algorithm> using namespace std; char str[160][160]; int N, M, T, city, maxn; int hash[5000]; int mp[510][510]; int xx[] = {0, 1, -1, 0}; int yy[] = {1, 0, 0, -1}; int match[510]; bool color[510]; int jugde( int x, int y ) { if( x < 1 || x > N || y < 0 || y >= M) return 0; return 1; } void Creat_Graph(int x, int y) { for( int i = 0; i < 4; i++) { int x1 = x + xx[i]; int y1 = y + yy[i]; int a = hash[x * maxn + y]; int b = hash[x1 * maxn + y1]; if( jugde(x1, y1) && str[x1][y1] == '*') { mp[a][b] = 1; } } } int find( int x ) { for( int i = 1; i <= city; i++) { if( !color[i] && mp[x][i] ) { color[i] = true; if( match[i] == -1 || find( match[i] )) { match[i] = x; return 1; } } } return 0; } void solve( ) { int ans = 0; memset(match,-1,sizeof(match)); for( int i = 1; i <= city; i++) { memset(color, 0, sizeof(color)); if( find(i) ) ans++; } printf("%d\n",city - ans / 2); } int main( ) { char c[10]; scanf("%d",&T); while(T--) { scanf("%d%d",&N,&M); gets(c); city = 0; maxn = max( N, M ); memset(hash, 0, sizeof(hash)); memset(mp, 0, sizeof(mp)); for( int i = 1; i <= N; i++) gets(str[i]); for( int i = 1; i <= N; i++) { for( int j = 0; j < M; j++) { if( str[i][j] == '*' ) { ++city; hash[i * maxn + j] = city; } } } //构图 for( int i = 1; i <= N; i++) { for( int j = 0; j < M; j++) { if( str[i][j] == '*' ) Creat_Graph(i, j); } } solve( ); } return 0; }