CF #541 (Div. 2)-D. Gourmet choice(拓扑排序,并查集缩点)
题目链接: D. Gourmet choice.
题意:要求给出两个分别包含n和m的序列使得该序列满足给出的大小关系,并且满足其中最大的元素最小,给出n*m的矩阵表示大小关系。
明显是一道拓扑排序的题。。比赛的时候没时间做了。。
有一点细节的是存在值相等的值,需要通过并查集进行缩点的处理,这样值相同的点只需要一个父节点来表示即可。
#include <iostream>
#include <vector>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <string>
#include <cstring>
using namespace std;
typedef long long ll;
const ll inf = 1e18;
const ll mod = 1e9 + 7;
int n, m;
int fa[2005];
char a[1005][1005];
int cnt[2005];
int ans[2005];
vector<int> v[2005];
queue<pair<int, int> > q;
int vis[2005];
int find(int x) {
if (x == fa[x]) return x;
else return fa[x] = find(fa[x]);
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%s", a[i] + 1);
for (int i = 1; i <= n + m; i++) fa[i] = i;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (a[i][j] == '=') {
int xx = find(i);
int yy = find(n + j);
fa[xx] = yy;
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
int xx = find(i);
int yy = find(n + j);
if (a[i][j] == '<') {
cnt[yy]++;
v[xx].push_back(yy);
} else if (a[i][j] == '>') {
cnt[xx]++;
v[yy].push_back(xx);
}
}
}
for (int i = 1; i <= n + m; i++) {
int xx = find(i);
if (cnt[xx] == 0 && !vis[xx]) {
vis[xx] = 1;
q.push(make_pair(xx, 1));
}
}
while (!q.empty()) {
int xx = q.front().first;
int yy = q.front().second;
ans[xx] = yy;
q.pop();
for (int i = 0; i < v[xx].size(); i++) {
cnt[v[xx][i]]--;
if (cnt[v[xx][i]] == 0) {
//printf("%d\n",v[xx][i]);
q.push(make_pair(v[xx][i], yy + 1));
}
}
}
for (int i = 1; i <= n + m; i++) {
int xx = find(i);
if (cnt[xx] != 0) {
printf("No");
return 0;
}
}
printf("Yes\n");
for (int i = 1; i <= n; i++) {
printf("%d ", ans[find(i)]);
}
printf("\n");
for (int i = 1; i <= m; i++) {
printf("%d ", ans[find(n + i)]);
}
return 0;
}