链接: 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
0−9每个数字的个数,现在要构造出一个没有前导
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
2∗maxv−sum≥1时,那就不行
如果这个最大数量不是拿的这个数,那么
2
∗
m
a
x
v
−
s
u
m
>
1
2*maxv-sum>1
2∗maxv−sum>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
如果你有任何建议或者批评和补充,请留言指出,不胜感激