小记:这题是暑期训练放在贪心这一章的题,我瞎蒙的, 没想到真的对了
思路:我的这个想法,我自己试了几组数据,也试图去举出点反例,但是都没用,答案都是正确的,而且也比较的简单可行,所以我抱着试试的态度做了。
贪心的思路就是,对方格的每个点记录下它上下左右四个方向所能覆盖的点的个数,
即因为你要放在这点上的话,那么这点的上下左右四个方向就不能再放了,当然碰到墙就打止
例如:
题目这组数据4 .X.. .... XX.. ....
那么转化过来就是
2 0 5 5
5 4 7 7
0 0 5 5
4 4 7 7
就这样
然后对个数值进行从小到大排序,依次选择,选择了该点之后,那么它所覆盖的点都不能在被选择了,标记起来即可。
答案就是你所选择的点的个数
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <map>
#include <set>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>
using namespace std;
#define mst(a,b) memset(a,b,sizeof(a))
#define REP(a,b,c) for(int a = b; a < c; ++a)
#define eps 10e-8
const int MAX_ = 110;
const int N = 100010;
const int INF = 0x7fffffff;
struct node{
int s, e;
int num;
}t[MAX_];
int vis[MAX_][MAX_];
char str[MAX_][MAX_];
bool cmp(const node& a, const node& b)
{
return a.num < b.num;
}
int main()
{
int T;
int n, m;
//scanf("%d",&T);
while(scanf("%d",&n), n) {
REP(i, 0, n){
scanf("%s", str[i]);
}
int cnt = 0;
//mst(vis, 0);
REP(i, 0, n){
REP(j, 0, n){
if(str[i][j] == '.'){
vis[i][j] = 0;
int tmp = 0;
int h = 0;
while(i-h > -1 && str[i-h][j] == '.'){h++; tmp++;}
h = 1;
while(i+h < n && str[i+h][j] == '.'){h++; tmp++;}
h = 1;
while(j-h > -1 && str[i][j-h] == '.'){h++; tmp++;}
h = 1;
while(j+h < n && str[i][j+h] == '.'){h++; tmp++;}
t[cnt].s = i;
t[cnt].e = j;
t[cnt].num = tmp;
cnt++;
}else vis[i][j] = 1;
}
}
sort(t, t+cnt, cmp);
int ans = 0;
REP(i, 0, cnt){
int x = t[i].s, y = t[i].e;
if(!vis[x][y]){
ans++;
int h = 0;
while(x-h > -1 && str[x-h][y] == '.'){vis[x-h][y] = 1;h++; }
h = 1;
while(x+h < n && str[x+h][y] == '.'){vis[x+h][y] = 1;h++; }
h = 1;
while(y-h > -1 && str[x][y-h] == '.'){vis[x][y-h] = 1;h++; }
h = 1;
while(y+h < n && str[x][y+h] == '.'){vis[x][y+h] = 1;h++; }
}
}
printf("%d\n", ans);
}
return 0;
}