题目链接:https://codeforces.com/problemset/problem/1131/D
题目大意:
共有n+m道菜,美食家知道这些菜两两之间的好坏,问你这m+n道菜每一道菜的分数是多少?最差的菜分数是1,依照好的程度向上+1。两道菜比较之间好坏分数可能相同。如果不存在答案输出No,否则输出Yes和每一道菜的分数。
解题思路:
由于有相同分数的菜,我们可以先用并查集维护分数相同的菜种,再检查会不会有冲突的情况(同一个unit但是却有大小之分),有冲突直接输出No,否则进入dfs遍历图。注意要缩点,只需要每一个unit的根建图。缩点之后图是单向的,如果图有环也输出No。这里要用记忆化搜索,更新过的点就不必再dfs了,否则超时。最后根据unit的根更新所有点的答案就可以了。
代码如下:
# include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 5;
int n, m;
int ans[maxn*2], indeg[maxn*2], vis[maxn*2], fa[maxn*2];
char s[maxn][maxn];
vector <int> G[maxn*2];
int Find(int v){
return fa[v] == v ? v : fa[v] = Find(fa[v]);
}
void unite(int x, int y){
x = Find(x);
y = Find(y);
if(x == y) return ;
fa[y] = x;
}
bool same(int x, int y){
return Find(x) == Find(y);
}
int max(int x, int y){
return x > y ? x : y;
}
int dfs(int v){
if(ans[v] != 1) return ans[v];
if(vis[v]){ //形成了一个环
cout << "No" << endl;
exit(0);
}
vis[v] = 1;
for(int i = 0; i < G[v].size(); ++i){
int w = G[v][i];
if(!same(v, w)) ans[v] = max(ans[v], dfs(w)+1); //不相同,向上+1
else ans[v] = max(ans[v], dfs(w)); //相同不加
}
vis[v] = 0;
return ans[v];
}
int main(){
std::ios::sync_with_stdio(false);
cin >> n >> m;
for(int i = 0; i <= n+m; ++i) fa[i] = i;
for(int i = 0; i <= m+n; ++i) ans[i] = 1;
for(int i = 1; i <= n; ++i)
cin >> s[i]+1;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
if(s[i][j] == '=') unite(i, j+n);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j){
if(s[i][j] == '>'){
int fx = Find(i), fy = Find(j+n);
if(fx == fy){
cout << "No" << endl;
return 0;
}
G[fx].push_back(fy); //并查集缩点,再记忆化dfs
indeg[fy]++;
}
else if(s[i][j] == '<'){
int fx = Find(i), fy = Find(j+n);
if(fx == fy){
cout << "No" << endl;
return 0;
}
G[fy].push_back(fx);
indeg[fx]++;
}
else{
G[i].push_back(j+n);
indeg[j+n]++;
unite(i, j+n);
}
}
for(int i = 1; i <= n+m; ++i)
if(indeg[i] == 0 && G[i].size())
dfs(i);
for(int v = 1; v <= m+n; ++v){
int fa = Find(v);
ans[v] = ans[fa];
}
for(int v = 1; v <= m+n; ++v){
for(auto w: G[v]){
if((same(v, w) && ans[v] != ans[w]) || (!same(v, w) && ans[v] <= ans[w])){
cout << "No" << endl;
return 0;
}
}
}
cout << "Yes" << endl;
for(int i = 1; i <= n; ++i)
cout << ans[i] << ' ';
cout << endl;
for(int i = n+1; i <= m+n; ++i)
cout << ans[i] << ' ';
cout << endl;
return 0;
}