题意:n*m的格子只有k个位置可以放置棋子,给出这k个位置。同一行或同一列的棋子之间会冲突。若这k个位置中某个位置变成了不可放棋子的位置,可放棋子数减少了,那么这样的位置称为重要点。求在摆放棋子最多的情况下问有多少个重要点。
题解:最大匹配数
1.棋子放在一个位置等价于一行匹配一列,就转化为了最大匹配数问题。这就算出了棋子摆放的最多数目。
2.枚举k个位置,每次枚举减少一个位置,计算最多能摆放几个棋子,若小于最多摆放数目,则该位置是重要点。
3.used[j]=i表示第i行第j列存在一个棋子,used数组是理解这道题的关键。
4.套用匈牙利模板即可。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#include<math.h>
using namespace std ;
int n , m , k ;
int x[10005] , y[10005] ;
int map1[105][105] ;
int used[105] ;
bool vis[105] ;
bool find(int u)
{
int i , j ;
for(i = 1 ; i <= m ; i ++)
{
if(map1[u][i] && !vis[i])
{
vis[i] = 1 ;
if(used[i] == 0 || find(used[i]))
{
used[i] = u ;
return 1 ;
}
}
}
return 0 ;
}
int Match()
{
int i , j , k ;
int ans = 0 ;
memset(used , 0 , sizeof(used)) ;
//used[j] = i 表示第i行第j列已摆放棋子
//理解这个数组就理解了这种类八皇后问题
for(i = 1 ; i <= n ; i ++)
{
memset(vis , 0 , sizeof(vis)) ;
if(find(i))
ans ++ ;
}
return ans ;
}
int main()
{
int i , j , k ;
int ans , temp ;
int cnt = 0 ;
int num ;
while(scanf("%d%d%d" , &n , &m , &k) != EOF)
{
memset(map1 , 0 , sizeof(map1)) ;
for(i = 1 ; i <= k ; i ++)
{
scanf("%d%d" , &x[i] , &y[i]) ;
map1[x[i]][y[i]] = 1 ;
}
ans = Match() ;
num = 0 ;
for(i = 1 ; i <= k; i ++)
{
map1[x[i]][y[i]] = 0 ;
//该点若不能放棋子,那么总棋子数是否会减少。
//若会减少,则该点是重要点。
temp = Match() ;
if(temp < ans)
num ++ ;
map1[x[i]][y[i]] = 1 ;
}
printf("Board %d have %d important blanks for %d chessmen.\n" , ++cnt , num , ans) ;
}
}