Codeforces Round #541 (Div. 2)D. Gourmet choice(拓扑排序+并查集+思维)

10 篇文章 1 订阅
6 篇文章 0 订阅

题目链接:https://codeforces.com/contest/1131/problem/D

 

题目大意:给出n个数和m个数之间分别的大小关系,求使得最大数最小的情况

 

题目思路:如果全是>或者<这道题很简单,直接建图就结束了,但是这里有个=。这个等于的解决非常巧妙,使用并查集将=的点并在一起缩点然后这道题就转换成了只有>或<的情况

 

以下是代码:

#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<math.h>
using namespace std;
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(ll i=a;i<=b;i++)
#define per(i,a,b) for(ll i=a;i>=b;i--)
#define ll long long
const ll MAXN = 2e3+5;
const ll MOD = 1e9+7;
int n,m,a[MAXN],vis[MAXN],pre[MAXN];
vector<int>v[MAXN];
char mp[MAXN][MAXN];
struct node{
    int x,val;
}p;
queue<node>q;
int Find(int x){
    return pre[x]==x?x:pre[x]=Find(pre[x]);
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        int flag=0;
        memset(vis,0,sizeof(vis));
        memset(a,0,sizeof(a));
        rep(i,1,n+m)pre[i]=i;
        rep(i,1,n){
            scanf("%s",mp[i]+1);
        }
        rep(i,1,n){
            rep(j,1,m){
                if(mp[i][j]=='='){
                    int xx=Find(i),yy=Find(n+j);
                    pre[xx]=yy;
                }
            }
        }
        rep(i,1,n){
            rep(j,1,m){
                if(mp[i][j]=='=')continue;
                int xx=Find(i),yy=Find(n+j);
                if(xx==yy){
                    flag=1;
                    break;
                }
                if(mp[i][j]=='<'){
                    v[xx].push_back(yy);
                    vis[yy]++;
                }
                if(mp[i][j]=='>'){
                    v[yy].push_back(xx);
                    vis[xx]++;
                }
            }
            if(flag)break;
        }
        if(flag){
            puts("No");
            continue;
        }
        rep(i,1,n){
            if(vis[i]==0){
                p.x=i,p.val=1;
                q.push(p);
            }
        }
        rep(i,1,m){
            if(vis[n+i]==0){
                p.x=n+i,p.val=1;
                q.push(p);
            }
        }
        int tot=0;
        while(!q.empty()){
            tot++;
            p=q.front();
            q.pop();
            a[p.x]=p.val;
            int len=v[p.x].size();
            rep(i,0,len-1){
                int to=v[p.x][i];
                vis[to]--;
                if(!vis[to]){
                    node temp;
                    temp.x=to,temp.val=p.val+1;
                    q.push(temp);
                }
            }
        }
        rep(i,1,n+m){
            a[i]=a[Find(i)];
        }
        rep(i,1,n){
            rep(j,1,m){
                if((mp[i][j]=='='&&a[i]==a[n+j])||(mp[i][j]=='>'&&a[i]>a[n+j])||(mp[i][j]=='<'&&a[i]<a[n+j]))flag=0;
                else{
                    flag=1;
                    break;
                }
            }
            if(flag)break;
        }
        if(flag)printf("No\n");
        else{
            printf("Yes\n");
            rep(i,1,n+m){
                printf("%d",a[i]);
                if(i==n||i==n+m)cout<<endl;
                else cout<<" ";
            }
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值