优先队列实现字典序最小的拓扑排序

链接:https://ac.nowcoder.com/acm/contest/5678/B
来源:牛客网

烦人的依赖
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
Ubuntu20.04 正式发布了,ZLS 是一个作死小能手,于是他决定尝试一下这个船新版本。好不容易装完系统,ZLS 想要给他的系统装一些常用的软件。众所周知,在 Linux 装软件会遇到各种奇奇怪怪的依赖问题(所谓依赖问题就是若A依赖B,则B要先与A安装)。ZLS 对此不厌其烦,因此他想知道他要用什么顺序安装软件,可以一次安装成功呢?
Tips: ZLS 还有一个癖好,他喜欢先安装字典序小的软件。
输入描述:
第一行包含一个正整数 T 表示数据组数。
每组数据的第一行包 n 和 m, 表示有 n 个软件,m 个依赖关系。
接下来的一行包含 n 个软件名(软件名仅包含小写字母 a-z )
接下来的 m 行每行有两个软件名 s 和 t,表示 t 依赖 s ,即 s 要在 t 之前安装。
数据保证: 1 \le T \le 51≤T≤5
1 \le n \le 3 \times 10^{4}, 1 \le m \le 10^{5}1≤n≤3×10
4
,1≤m≤10
5

1 \le |s|,|t| \le 101≤∣s∣,∣t∣≤10
输出描述:
共 T 组输出,每组输出先输出一行 Case #%d: ,%d 替换为当前输出的组数。
接下来是 n 行,按照安装的顺序输出。
如果无法进行安装,输出 Impossible (注意大小写)。
示例1
输入
复制
2
4 2
a b c d
a b
b c
3 3
a b c
a b
b c
c a
输出
复制
Case #1:
a
b
c
d
Case #2:
Impossible

我们输出的顺序就是拓扑排序,只是要求是字典序最小,那么就将队列用优先队列替换即可,然后我们需要将各个字符映射成一个个结点,按照从小到大的顺序排序,然后在编号,然后拓扑排序一遍即可。

#include<bits/stdc++.h>
#include<iostream>
#include<map>
#include <cstring>
using namespace std;
const int maxn=1e6;
int ru[maxn];
int grp[3005][3005];
int ans[maxn];
vector<int>res;
vector<int>edge[30005];
//queue<int>q;
//priority_queue<int,vector<int>,greater<int> >q;
priority_queue<int> q;
string st[maxn];
//unordered_map<string,int>st1;
map<string,int>st1;
int jl=0;
void cl(int n)
{
    memset(ru,0,sizeof ru);
    while(!q.empty())
        q.pop();
    st1.clear();
    for(int i=1;i<=n;i++)
        edge[i].clear();
    res.clear();
}
int main()
{
int t;
cin>>t;
while(t--)
{
int n,m;
cin>>n>>m;
cl(n);
for(int i=1;i<=n;i++)
{
    cin>>st[i];
}
 sort(st+1, st+n+1, greater<string>());
for(int i=1;i<=n;i++)
    st1[st[i]]=i;

for(int i=1;i<=m;i++)
{
    string u,v;
    cin>>u>>v;
   edge[st1[u]].push_back(st1[v]);
    ru[st1[v]]++;

}
for(int i=1;i<=n;i++)
{
    if(ru[i]==0)
        q.push(i);
}
while(!q.empty())
{
    //int p=q.front();
    int p=q.top();
    //cout<<p<<endl;
    q.pop();
    res.push_back(p);
    for(int i=0;i<edge[p].size();i++)
    {
        int y=edge[p][i];
        ru[y]--;
        if(ru[y]==0)
        {
            q.push(y);
        }
    }
}
cout<<"Case #"<<++jl<<":"<<endl;
if(res.size()<n)
    cout<<"Impossible"<<endl;
else
{
    for(int i=0;i<res.size();i++)
        cout<<st[res[i]]<<endl;
}
}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值