UVA1103 古代象形符号 Ancient Messages

首先是理解题意,这个刘汝佳写的很明白了,其实就是找1里面包着的有多少个0的连通块,不同的1的块互不干扰不相邻不包含,然后我就看uva上的例子,想把16进制化成2进制然后看是不是对的上,结果硬是对不上号,上面有很多省略的行,弄的我是一头雾水,无奈去uDbug上面复制几个样例,输入转换一下才确定题意就是这么回事,然后开始想题,

一开始硬是想不起来,怎么才能确定一个0连通块是在1里面的,终于想到可以设置一个辅助的数组,一般这种dfs需要两个数组,一个存数据,一个存是否访问,现在我们遍历数组,一旦遇到一个1连通块,我们在dfs的时候,也对设置的辅助数组进行更改,最终辅助数组只有当前这个1连通块,其余都是0,接下来我们就能对两个辅助数组进行第二种dfs,来数0连通块个数的dfs,数出来减一就是结果,

结果还有一个数据点没过,才发现如果一个1连通块里面不含0,但是它和边界相连,是可能造成0的连通块个数不为1,而是23456,,,的情况的,又开始想怎么解决这个,想了两分钟才想到可以设置辅助数组的时候行数+2列数+2,就是在外面填充一圈零,这样原始数组里面不属于1连通块的,但是被1连通块分割的0连通块就连到一起了,只需要减一就行了,然后稍微修改了一下,原始数组里面的0,0位置的放到1,1,以此类推,就可以了,

看看题解的时候学习了另外一种思路,就是找黑色连通块的时候给它做好标记,然后找白色连通块,如果它和边界挨着,也就是递归的时候可以到四个边界,那么它是肯定不被黑色连通块包围的,对剩下的白色连通块dfs,看看递归到的黑色连通块的标记,那么它就是属于这个黑色连通块的,

#include <bits/stdc++.h>

#define fi first
#define se second
#define pb push_back
#define mk make_pair
#define sz(x) ((int) (x).size())
#define all(x) (x).begin(), (x).end()

using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef pair<int, int> pa;

const int N = 205;

int h, w;
int mat[N][N], vis[N][N], Hash[N][N], vis2[N][N];
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
char str[20] = "WAKJSD";
int rec[20][4] = {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1,
                  0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1,
                  1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1,
                  1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1};

void dfs(int x, int y) {
    vis[x][y] = 1;
    Hash[x + 1][y + 1] = 1;
    for (int i = 0; i < 4; i++) {
        int r = x + dx[i];
        int c = y + dy[i];
        if (r < 0 || r >= h || c < 0 || c >= w) continue;
        if (!vis[r][c] && mat[r][c]) dfs(r, c);
    }
}

void dfs2(int x, int y) {
    vis2[x][y] = 1;
    for (int i = 0; i < 4; i++) {
        int r = x + dx[i];
        int c = y + dy[i];
        if (r < 0 || r >= h + 2 || c < 0 || c >= w + 2) continue;
        if (!vis2[r][c] && !Hash[r][c]) dfs2(r, c);
    }
}

int main() {
    int num = 1;
    while (cin >> h >> w && h) {
        memset(mat, 0, sizeof(mat));
        memset(vis, 0, sizeof(vis));
        for (int i = 0; i < h; i++) {
            string s;
            cin >> s;
            for (int j = 0; j < sz(s); j++) {
                if (s[j] == '0') continue;
                int t;
                if (isdigit(s[j])) t = s[j] - '0';
                else t = s[j] - 'a' + 10;
                for (int k = j * 4; k < j * 4 + 4; k++) {
                    mat[i][k] = rec[t][k - j * 4];
                }
            }
        }
        w *= 4;
        vector<char> vec;
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                if (mat[i][j] && !vis[i][j]) {
                    memset(Hash, 0, sizeof(Hash));
                    memset(vis2, 0, sizeof(vis2));
                    int cnt = 0;
                    dfs(i, j);
                    for (int ii = 0; ii < h + 2; ii++) {
                        for (int jj = 0; jj < w + 2; jj++) {
                            if (!Hash[ii][jj] && !vis2[ii][jj]) {
                                cnt++;
                                dfs2(ii, jj);
                            }
                        }
                    }
                    vec.pb(str[cnt - 1]);
                }
            }
        }
        sort(all(vec));
        cout << "Case " << num++ << ": ";
        for (int i = 0; i < sz(vec); i++) cout << vec[i];
        cout << endl;
    }
    return 0;
}

接下来是补一下之前看的思路,主要就是3个深搜,第一个是遍历黑像素,然后给其上标号,第二个是遍历白像素,给其上标号,同时如果搜索过程中遇到了边界,那么标记一下这个标号,就是具有这个标号的白像素是和边界想连的,第三个是遍历不和边界想连的白像素,这时它一定是包围在某个黑像素之内的,遍历的时候遇到,就记录一下遇到的是哪个标号的黑像素,搜索完之后加一,表明这个黑连通块有白块的个数加一,最后统计结果输出,这个复杂度明显比上一个小,但是20ms比50ms感觉提升不大

#include <bits/stdc++.h>

#define fi first
#define se second
#define pb push_back
#define mk make_pair
#define sz(x) ((int) (x).size())
#define all(x) (x).begin(), (x).end()

using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef pair<int, int> pa;

const int N = 205;

char str[10] = "WAKJSD";
int h, w, mat[N][N], vis[N][N], vis2[N][N], vis3[N][N], cnt, tot, cur;
int Hash[N * N], rec[N * N];
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
int num[20][4] = {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1,
                  0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 
                  1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1,
                  1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1};

void dfs(int x, int y) {
    vis[x][y] = cnt;
    for (int i = 0; i < 4; i++) {
        int r = x + dx[i];
        int c = y + dy[i];
        if (r < 0 || r >= h || c < 0 || c >= w) continue;
        if (mat[r][c] && !vis[r][c]) dfs(r, c);
    }
}

void dfs2(int x, int y) {
    vis2[x][y] = cnt;
    for (int i = 0; i < 4; i++) {
        int r = x + dx[i];
        int c = y + dy[i];
        if (r < 0 || r >= h || c < 0 || c >= w) { Hash[cnt] = 1; continue; }
        if (!mat[r][c] && !vis2[r][c]) dfs2(r, c);
    }
}

void dfs3(int x, int y) {
    vis3[x][y] = 1;
    for (int i = 0; i < 4; i++) {
        int r = x + dx[i];
        int c = y + dy[i];
        if (mat[r][c]) { cur = vis[r][c]; continue; }
        if (!vis3[r][c]) dfs3(r, c);
    }
}

int main() {
    int Case = 1;
    while (cin >> h >> w && h) {
        for (int i = 0; i < h; i++) {
            string s;
            cin >> s;
            for (int j = 0; j < w; j++) {
                for (int k = j * 4; k < j * 4 + 4; k++) {
                    if (isdigit(s[j])) mat[i][k] = num[s[j] - '0'][k - j * 4];
                    else mat[i][k] = num[s[j] - 'a' + 10][k - j * 4];
                }
            }
        }
        w *= 4;
        cnt = 1;
        memset(vis, 0, sizeof(vis));
        memset(vis2, 0, sizeof(vis2));
        memset(Hash, 0, sizeof(Hash));
        memset(rec, 0, sizeof(rec));
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                if (mat[i][j] && !vis[i][j]) { dfs(i, j); cnt++; }
            }
        }
        tot = cnt - 1;
        cnt = 1;
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                if (!mat[i][j] && !vis2[i][j]) { dfs2(i, j); cnt++; }
            }
        }
        memset(vis3, 0, sizeof(vis3));
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                if (!mat[i][j] && !vis3[i][j] && !Hash[vis2[i][j]]) { dfs3(i, j); rec[cur]++; }
            }
        }
        vector<char> ans;
        for (int i = 1; i <= tot; i++) ans.pb(str[rec[i]]);
        sort(all(ans));
        cout << "Case " << Case++ << ": ";
        for (int i = 0; i < sz(ans); i++) cout << ans[i];
        cout << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值