2021 Jiangsu Collegiate Programming Contest(C、J)

链接: link.

J - Anti-merge

题意:
给定一个 N × M N×M N×M的矩阵,矩阵内相同的数字相邻时有按照列优先行其次的优先级进行合并,现在让你给一些数字贴上标签,若两个相邻数字相同但标签不同时,不会合并,但标签一样,数字一样时,会合并,问最少贴多少种标签,且在标签种类最少时,最少贴多少个标签
思路:
如果矩阵中不会出现合并现象,即没有相邻数字一样时,直接就输出 0 0 0即可。
如果矩阵中有合并现象,那么 标签种类一定最少一定是 1 1 1,因为合并现象指挥发生在相邻且相同的数字之间,那么只需要给相同数字且相邻的贴上标签 1 1 1,另一个不贴标签,就能区分开两种数字,使其不合并,所以标签种类最少是 1 1 1,标签种类为 1 1 1的情况下,就是二分图染色,把格点看成图中的点,相邻就是连边,那么直接跑二分图就行,对每一个部分染色后,看哪种颜色少,就把哪种存到答案中。

#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
const int N = 555;
int n, m;
typedef pair<int, int> PII;
int a[N][N];
vector<PII> ans[4];
int color[N][N];
int dx[4] = {-1, 1, 0, 0};
int dy[4] = {0, 0, -1, 1};

int check(int x, int y) {
    int flag1 = 0, flag2 = 0;
    if (x - 1 > 0 && a[x - 1][y] == a[x][y]) flag1 = 1;
    if (y - 1 > 0 && a[x][y - 1] == a[x][y]) flag2 = 1;
    return (flag1 | flag2);
}

bool dfs(int x, int y, int c) {
    color[x][y] = c;
    ans[c].push_back({x, y});
    for (int i = 0; i < 4; i++) {
        int nx = x + dx[i];
        int ny = y + dy[i];
        if (nx < 1 || nx > n || ny < 1 || ny > m || a[x][y] != a[nx][ny]) {
            continue;
        }
        if (!color[nx][ny]) {
            if (!dfs(nx, ny, 3 - c)) return 0;
        } else if (color[nx][ny] == c) {
            return 0;
        }
    }
    return 1;
}
int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            scanf("%d", &a[i][j]);
        }
    }

    int types = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (check(i, j)) {
                types = 1;
                break;
            }
        }
        if (types) break;
    }
    if (!types) {
        puts("0 0");
    } else {
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                ans[1].clear();
                ans[2].clear();
                if (!color[i][j]) {
                    dfs(i, j, 1);
                }
                if (ans[1].size() > ans[2].size()) {
                    for (int k = 0; k < ans[2].size(); k++) {
                        ans[0].push_back(ans[2][k]);
                    }
                } else {
                    for (int k = 0; k < ans[1].size(); k++) {
                        ans[0].push_back(ans[1][k]);
                    }
                }
            }
        }
        cout << types << " " << ans[0].size() << endl;
        for (int i = 0; i < ans[0].size(); i++) {
            cout << ans[0][i].first << " " << ans[0][i].second << " "
                 << "1" << endl;
        }
    }
    return 0;
}

C - Magical Rearrangement

题意:
给出 0 − 9 0-9 09每个数字的个数,现在要构造出一个没有前导 0 0 0( 0 0 0本身除外),且相邻数字不能一样的数字,这个数字最小是多少?
思路:
从小到大贪心,在贪心过程中,每次取一个数的时候判断即可,如果剩下的数字总数为 s u m sum sum,最大的数量为 m a x v maxv maxv
如果这个最大的数量就是拿的这个数,那么 2 ∗ m a x v − s u m ≥ 1 2*maxv-sum≥1 2maxvsum1时,那就不行
如果这个最大数量不是拿的这个数,那么 2 ∗ m a x v − s u m > 1 2*maxv-sum>1 2maxvsum>1时,那就不行

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int a[11];
int res[N];

bool check(int u) {
    int sum = 0;
    int maxv = 0;
    for (int i = 0; i < 10; i++) {
        sum += a[i];
        maxv = max(maxv, a[i]);
    }
    for (int i = 0; i < 10; i++) {
        if (a[i] == maxv) {
            if (i == u) {
                if (2 * maxv - sum >= 1) {
                    return 0;
                }
            } else {
                if (2 * maxv - sum > 1) {
                    return 0;
                }
            }
        }
    }
    return 1;
}
int main() {
    int T;
    cin >> T;
    while (T--) {
        int all = 0;
        for (int i = 0; i < 10; i++) {
            scanf("%d", &a[i]);
            all += a[i];
        }
        memset(res, 0, (all + 2) * 4);
        if (all == 1) {
            for (int i = 0; i < 10; i++) {
                if (a[i]) {
                    printf("%d\n", i);
                }
            }
        } else {
            bool flag = 1;
            int ed = all;
            int st = 0;
            while (st < ed) {
                bool f = 1;
                for (int i = 0; i < 10; i++) {
                    if (st == 0 && i == 0) continue;
                    if (a[i] == 0) continue;
                    if (st != 0 && res[st - 1] == i) continue;
                    a[i]--;
                    if (check(i)) {
                        res[st++] = i;
                        f = 0;
                        break;
                    } else {
                        a[i]++;
                    }
                }
                if (f) {
                    flag = 0;
                    break;
                }
            }
            if (flag == 0) {
                puts("-1");
            } else {
                for (int i = 0; i < st; i++) {
                    cout << res[i];
                }
                puts("");
            }
        }
    }
    return 0;
}

剩下的待补
To be continued
如果你有任何建议或者批评和补充,请留言指出,不胜感激

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值