cf1113-d Gourmet choice

公开20190329远古博客,汗

一开始想用每一行的信息,把所有数分成三部分:<bi、=bi、>bi按照这个标准分成三部分,之后对n行的三个集合,取交balabala,感觉会取乱掉,就想着排序设各个小集合边节点,边节点区间取同一个值,好像乱掉了,拆分成集合。。。好迷

找题解看了一眼,最后自己实现的时候,把相等的用并查集设成同一个祖先,再用拓扑排序,由小指大的,最初压入队列的点val设为1,其余点的val为导出其的点val+1,过啦。

ac代码:

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
int fa[2005],du[2005],val[2005];
char a[1005][1005];
vector<int>v;
map<pii,int>mp;
vector<int>edge[2005];
queue<int>q;

int fin(int x)
{
    return fa[x] == x ? x : fa[x] = fin(fa[x]);
}

void unio(int a,int b)
{
    int faa = fin(a);
    int fab = fin(b);
    if(faa == fab)
        return ;
    fa[faa] = fab;
}


int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    ///1,,,n,n+1,,,n+m
    for (int i =1;i<=m+n;i++)
        fa[i] = i;
    for (int i = 1;i<=n;i++)
    {
        scanf("%s",a[i]+1);
        for (int j = 1;j<=m;j++)
        {
            if(a[i][j] == '=')
                unio(i,j+n);
        }
    }
    for (int i = 1;i<=n+m;i++)
        v.push_back(fin(i));
    for (int i = 1;i<=n;i++)
    {
        for (int j=n+1;j<=n+m;j++)
        {
            if(a[i][j-n] == '<' && !mp[{fa[i],fa[j]}])
                edge[fa[i]].push_back(fa[j]),mp[{fa[i],fa[j]}]++,du[fa[j]]++;
            else if(a[i][j-n] == '>' && !mp[{fa[j],fa[i]}])
                edge[fa[j]].push_back(fa[i]),mp[{fa[j],fa[i]}]++,du[fa[i]]++;
        }
    }
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    int len = v.size();
    for (int i = 0;i < len;i ++)
    {
        if(du[v[i]] == 0)
        {
            val[v[i]] = 1;
            q.push(v[i]);
        }
    }
    int cnt = 0;
    while(!q.empty())
    {
        int tmp = q.front();
        q.pop();
        cnt++;
        int len = edge[tmp].size();
        for (int i = 0;i<len;i++)
        {
            int x = edge[tmp][i];
            du[x]--;
            if(val[x])
                continue;
            if(!du[x])
            {
                val[x] = val[tmp]+1;
                q.push(x);
            }
        }
    }
    if(cnt < len)
        puts("No");
    else
    {
        puts("Yes");
        for (int i = 1;i <= n+m;i ++)
        {
            printf("%d%c",val[fa[i]],(i == n || i == n+m) ? '\n' : ' ');
        }
    }
}

根据这道题还有上次线段树优化建图拓扑排序:根据哈希线性探测之后存的位置,找出字典序最小的可能排序。

发现这些有特定的a必须在b前面(a必须比b小)的关系,复杂的交错融合之后,不容易找出一种分堆排序(桶排序)的方式,而拓扑排序很好的将所有特定条件完成了,并且解决了交错融合问题,因为交错融合情况下找出一组满足题意解即可,而拓扑排序就是利用特定关系建图,然后“排序"输出的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值