Codeforces Round #541 (Div. 2) 1131D. Gourmet choice 头铁大模拟(std拓扑排序+并查集

11 篇文章 0 订阅
4 篇文章 0 订阅

原题链接
题意:
有个厨师吃了2天,第一个天吃了n道菜,第二天吃了m道菜,然后给每道菜打分,给出一个n*m的字符矩阵,s[i][j]表示第一天的第i道菜和第二天的第j道菜的评分的大小关系,求这两天吃的菜的评分。

思路:
按>和=数量排序,先给最大的赋值1e4,每次取两个字符串对比,讨论一下各种组合情况,判掉不合法情况,求出第一天的评分,再根据每一列的符号求出第二天的评分。这时候求出来的只是相对大小,还要把所有的值在数轴上往左移,把最小的数移到1就可以了,细节比较多,很锻炼码力。

改到wa9的时候搜了一下题解,看到tag是拓扑排序+并查集,想了一会儿并没有思路,然后觉得模拟思路肯定没问题,只是有地方没考虑到,就继续干了(不得不说还是早上状态比较好,前一天晚上改到23点已经绝望了,第二天一来唰唰唰十分钟就想明白了)。

#include<bits/stdc++.h>
#define LL long long
#define INF INT64_MAX
#define MOD 998244353
#define ls rt << 1
#define rs rt << 1 | 1
using namespace std;
typedef pair<int,int>pa;
const int N = 1e3+7;
struct node{
    int pos, ma, dy;
}a[N];
int ans1[N], ans2[N];
string s[N];
bool cmp(node x, node y){
    if(x.ma==y.ma) return x.dy>y.dy;
    else return x.ma>y.ma;
}
int main(){
    int n, m, k, fla = 0, f = 0;
    scanf("%d%d", &n, &m);
    for(int i = 0;i < n;i++){
        cin>>s[i];
        a[i].pos = i;
        for(int j = 0;j < m;j++){
            if(s[i][j]=='>') a[i].ma++;
            else if(s[i][j]=='=') a[i].dy++;
        }
    }
    sort(a, a+n, cmp);
    ans1[a[0].pos] = 1e4;
    for(int i = 0;i < n-1;i++){
        f = 0;
        int oid = a[i].pos, id = a[i+1].pos;
        //printf("oid = %d %d\n", oid, id);
        if(s[oid]<s[id]){
            fla = 1;
        }
        for(int j = 0;j < m;j++){
            if(s[oid][j]=='>'){
                if(s[id][j]=='>') continue;
                if(s[id][j]=='='){                                       //比上一个小1的情况
                    if(f==1) fla = 1;
                    f = 2;
                    if(ans1[id]) ans1[id] = min(ans1[id], ans1[oid]-1);  //这里要取最小值
                    else ans1[id] = ans1[oid]-1;
                } else {
                    if(f==1) fla = 1;
                    f = 2;
                    ans1[id] = ans1[oid]-2;                              //比上一个小2的情况
                }
            }
            else if(s[oid][j]=='='){
                if(s[id][j]=='='){                                       //和上一个相等的情况
                    if(f==2) fla = 1;
                    f = 1;
                    ans1[id] = ans1[oid];
                }
                else if(s[id][j]=='>') fla = 1;
                else{                                                    //比上一个小1的情况
                    if(f==1) fla = 1;
                    f = 2;
                    if(ans1[id]) ans1[id] = min(ans1[id], ans1[oid]-1);  //这里要取最小值
                    else ans1[id] = ans1[oid]-1;
                }
            }
            else if(s[oid][j]=='<' && s[id][j]!='<') fla = 1;
        }
        if(!ans1[id]) ans1[id] = ans1[oid];                              //所有符号都一样的时候等于上一个数
    }
    if(fla){printf("No\n");return 0;}
    printf("Yes\n");
    for(int j = 0;j < m;j++){
        if(s[a[0].pos][j]=='<') {ans2[j] = ans1[a[0].pos]+1;continue;}           //第一个符号就是<
        if(s[a[n-1].pos][j]=='>'){ans2[j] = ans1[a[n-1].pos]-1; continue;}       //最后一个符号还是>
        if(ans1[a[0].pos]==ans1[a[n-1].pos]){ans2[j] = ans1[a[0].pos];continue;} //所有符号都是=
        for(int i = 0;i < n-1;i++){
            int id = a[i+1].pos, oid = a[i].pos;
            if(s[oid][j]=='>'){
                if(s[id][j]=='>') continue;
                else if(s[id][j]=='=') ans2[j] = ans1[id];               //等于第二个数
                else ans2[j] = ans1[id]+1;                               //在两个数中间
            }
            else if(s[oid][j]=='='){
                if(s[id][j]=='=') ans2[j] = ans1[id];                    //等于这两个数
                else ans2[j] = ans1[id]+1;                               //等于第一个数(也等于第二个数+1)
            }
            break;
        }
    }
    int Mi = 1e6;
    for(int i = 0;i < m;i++) Mi = min(Mi, ans2[i]);
    for(int i = 0;i < n;i++) Mi = min(Mi, ans1[i]);
    for(int i = 0;i < n;i++) printf("%d ", ans1[i]-Mi+1);
    printf("\n");
    for(int i = 0;i < m;i++) printf("%d ", ans2[i]-Mi+1);
    return 0;
}

补拓扑排序+并查集做法:
给n+m个点建有向边,大的指向小的,相等的用并查集相连,然后dfs跑到出度为0的点赋值1,再递归回去。

#include<bits/stdc++.h>
#define LL long long
#define INF INT64_MAX
#define MOD 998244353
#define ls rt << 1
#define rs rt << 1 | 1
using namespace std;
typedef pair<int,int>pa;
const int N = 2e3+7;
int a[N], f[N], vis[N];
char s[N][N];
vector<int> v[N];
int Find(int x){
    return x==f[x]? x : f[x]=Find(f[x]);
}
void Union(int x, int y){
    int fx = Find(x);
    int fy = Find(y);
    if(fx!=fy) f[fx] = fy;
}
void dfs(int x){
    vis[x] = 1;
    for(auto it:v[x]){
        if(vis[it]){
            printf("No\n");
            exit(0);
        }
        if(!a[it]) dfs(it);
        a[x] = max(a[x], a[it]);
    }
    ++a[x];
    vis[x] = 0;
}
int main(){
    int n, m, k;
    scanf("%d%d", &n, &m);
    for(int i = 1;i <= n+m;i++) f[i] = i;
    for(int i = 1;i <= n;i++){
        scanf("%s", s[i]+1);
        for(int j = 1;j <= m;j++){
            if(s[i][j]=='=') Union(i, j+n);
        }
    }
    for(int i = 1;i <= n;i++){
        for(int j = 1;j <= m;j++){
            if(s[i][j]=='>') v[Find(i)].push_back(Find(j+n));
            if(s[i][j]=='<') v[Find(j+n)].push_back(Find(i));
        }
    }
    for(int i = 1;i <= n+m;i++){
        if(!a[i]) dfs(i);
    }
    printf("Yes\n");
    for(int i = 1;i <= n;i++) printf("%d ", a[Find(i)]);
    printf("\n");
    for(int i = 1;i <= m;i++) printf("%d ", a[Find(i+n)]);
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值