[zoj3314]CAPTCHA超级大模拟2014.8.9

/*
 * 炒鸡大模拟.整体思想是读入数据后从上往下,从左往右扫描一遍,同时vis数组标记是否访问过,对于没有访问过且为'M'的点,就可以认为
 * 它是某个字母的组成部分了,因为组成每个字母的'M'间都是"邻居",所以从发现的这个'M'开始一次BFS/DFS就可以得到和这个'M'相连的
 * 所有'M',他们的个数也就是组成这个字母的'M'的个数喽.所以我们需要预处理每个字母对应由几个'M'组成.但是最后会发现有一些字母的
 * 'M'个数相同(比如T/C都是34个'M'组成),特判就好了.因此:
 * 先判每个字母有几个M组成. 然后对M个数相同的某几个找规律.比如C/T,你会发现不管C是上下对称的,
 * 所以当你对一个图从上往下,从左往右扫描到C的第一个'M'时,如果继续往右数连续的'M'个数,有且仅有8个!,而T则不然,
 * T倒过来时是2,顺着时是12(忘记了,反正比8大).这样就可以算是他们的"特征"了~~~对于其它字母也用一些小技巧找不同,
 * 这题相同的组数还是有不少的...当然,你很容易发现不同.比如...看扫描到的那一行有多少M,同时要注意翻转180度的,所以每个字母都
 * 不要忘记顺着看和倒过来看...
 * 总之就是找不同.最后输出注意下,因为要求字典序,或者用一个大小26的数组标记,或者每找到一个字母就丢到vector中,最后输出时我们对
 * 这堆字母排序,然后使用unique去重(http://www.cplusplus.com/reference/algorithm/unique/),因为如果一个字母出现多次,只能输出一次.开始用multiset就是没看清题目...
 * 还有数数时可以写个打表程序跑一下,当然我是先自己数,后来打表出来才发现V少数了一个- -||
 * 呃,总之如果自己数的话最后还是得打表验算一下的...
 */
#include <cstdio>
#include <cstring>
#include <set>
#include <iostream>
using namespace std;

const int MAX = 400;
char str[MAX][MAX];

int n, m;
bool vis[MAX][MAX];
int eight[8][2] = {-1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1};
int dfs(int x, int y) {
    int ans = 1, tx, ty;
    for (int i = 0; i < 8; ++i) {
        tx = x + eight[i][0];
        ty = y + eight[i][1];
        if (tx < 0 || ty < 0 || tx >= n || ty >= m || vis[tx][ty]) continue;
        if (str[tx][ty] == 'M') {
			vis[tx][ty] = true;
			ans += dfs(tx, ty);
		}
    }
    return ans;
}

char get(int x, int y) {
	int sum = dfs(x, y);
	if (sum == 22) return 'I';
	else if (sum == 24) return 'L';
	else if (sum == 27) return 'J';
	else if (sum == 28) return 'Y';
	else if (sum == 31) return 'Z';
	else if (sum == 33) return 'A';
	else if (sum == 37) return 'H';
	else if (sum == 44) return 'E';
	else if (sum == 48) return 'Q';
	else if (sum == 49) return 'B';
    else if (sum == 34) {
		int tmp = 0;
        for (int i = y; str[x][i] == 'M'; ++i, ++tmp);
        if (tmp == 8) return 'C';
        else return 'T';
    } else if (sum == 36) {
        int tmp = 0;
        for (int i = y; str[x][i] == 'M'; ++i, ++tmp);
        if (tmp == 4) return 'K';
        else if (tmp > 4) return 'F';
        else if (str[x+3][y+2] == 'M') return 'K';
        else return 'F';
    } else if (sum == 38) {
		int up = 0;
        for (int i = y; str[x][i] == 'M'; ++i, ++up);
        if (up == 8 || up == 9) return 'G';
        else if (up == 11) return 'P';
        else if (up == 10) return 'U';
        else if (str[x+6][y] == 'M') return 'P';
        else return 'U';
    } else if (sum == 40) {
		int tmp = 0;
		for (int i = y; str[x][i] == 'M'; ++i, ++tmp);
        if (tmp == 6) return 'O';
        else if (tmp == 4 || tmp == 0) return 'V';
        else if (tmp == 2) return 'W';
        else if (str[x+1][y] == 'M') return 'W';
        else return 'X';
    } else if (sum == 42) {
        int tmp = 0;
        for (int i = y; str[x][i] == 'M'; ++i, ++tmp);
        if (tmp == 11) return 'D';
        else if (tmp == 2) return 'M';
        else return 'N';
    } else if (sum == 43) {
        int tmp = 0;
        for (int i = y; str[x][i] == 'M'; ++i, ++tmp);
        if (tmp == 7 || tmp == 8) return 'S';
        return 'R';
    }
}
int main() {
    while (~scanf(" %d %d", &n, &m)) {
		memset(str, '\0', sizeof(str));
		for (int i = 0; i < n; ++i) scanf(" %s", str[i]);
        memset(vis, false, sizeof(vis));
        set<char> ans;
        for (int i = 0; i < n; ++i) {
			for (int j = 0; j < m; ++j) {
                if (!vis[i][j] && str[i][j] == 'M') {
					vis[i][j] = true;
                    ans.insert(get(i,j));
                }
			}
        }
        for (set<char>::iterator it = ans.begin(); it != ans.end(); ++it)
			putchar(*it);
		putchar('\n');
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值