题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=17335
题意:
给定一个棋盘,棋盘上有一些必须要覆盖的点。现在可以放一个车,车可以消掉同行和同列上的点。
思路:看题解做的。假定选定某些行,函数为m,在剩余空行上遍历,若空行列上还存在点,则标记该列。标记完以后,统计总共几个列被标记,设为n。因为一个车可以同时消去行和列,所以答案是gmax(m,n),然后找出所有选定行的最小的gmax(m,n),即为答案。二进制表示选取行的方法是一个亮点。
刚开始以为是猎人射鸟问题,即猎人不参与到格子中,一次只能选一列或者一行,所以用类似增广路的dfs做。
源码:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 15+2;
int id[32786];
char s[MAXN][MAXN];
int gmax(int a,int b){return a>b?a:b;}
int gmin(int a,int b){return a<b?a:b;}
int main()
{
int i,j,k;
id[0] = 0;
for(i=0; i<=32786; i++){///二进制表示一个数
id[i] = id[i>>1] + (i&1);
}
while(scanf("%s",s[0])!=EOF){
if(s[0][0]=='E')
return 0;
for(i=1; i<15; i++){
scanf("%s",s[i]);
}
int ans = 15;
for(i=0; i<(1<<15); i++){
int col[15];
memset(col,0,sizeof(col));
for(j=0; j<15; j++){
if((i&(1<<j))==0){
for(k=0; k<15; k++)
if(s[j][k]=='#')
col[k] = 1;
}
}
int tt = 0;
for(j=0; j<15; j++)
if(col[j]==1)
tt++;
tt = gmax(id[i],tt);
ans = gmin(ans,tt);
}
printf("%d\n",ans);
}
return 0;
}