题目链接

题意:给s个字符串,m个关系,n个字符串,当两个字符串满足m关系之一且相邻则在n个字符串中可交换,求n的最小。

思路:因为对于如果不满足关系的两个字符串a,b,若a在b前面,则a永远在b前面。所以可以利用不能交换的字符串做一个图,对其的拓扑序则为最后答案,因为当前面不能交换的先出队,后面的才能出队。当然要用优先队列,因为当多个点在队列时时,代表这些点的字符串是可交换的。因此要对其字典序小的更优先出队。

#include<bits/stdc++.h>
#include<vector>
using namespace std;
typedef long long LL;
const int maxn = 100000+10;
struct node
{
    int x,y;
};
int S,m,n,nn;
string s[1010];
map<string,int> mp;
bool f[210][210];
int last[210];
int nxt[maxn];
int a[maxn],du[maxn];
vector<int> G[maxn];
struct cmp
{
    bool operator()(int x,int y)
    {
        if (a[x]==a[y]) return x>y;
        return a[x]>a[y];
    }
};
 
int main()
{
    scanf("%d%d%d",&S,&m,&n);
    for(int i=1;i<=S;i++)
    {
        cin>>s[i];
    }
    sort(s+1,s+S+1);
    for(int i=1;i<=S;i++)
    {
        mp[s[i]]=i;
    }
    string s1,s2;
    for(int i=1;i<=m;i++)
    {
        cin >> s1 >> s2;
        f[mp[s1]][mp[s2]]=1;
        f[mp[s2]][mp[s1]]=1;
    }
    for(int i=1;i<=n;i++)
    {
        cin>>s1;
        a[i]=mp[s1];
    }
    memset(last,-1,sizeof(last));
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=S;j++)
        {
            if(f[a[i]][j]||last[j]==-1) continue;
            G[last[j]].push_back(i);
            du[i]++;
        }
        last[a[i]]=i;
    }
    priority_queue<int,vector<int>,cmp> que;
    for(int i=1;i<=n;i++)
    {
        if(du[i]==0) que.push(i);
    }
    int num=0;
    while(!que.empty())
    {
        int x=que.top();
        que.pop();
        cout<<s[a[x]]<<" ";
        for(auto v:G[x])
        {
            du[v]--;
            if(!du[v]) que.push(v);
        }
    }
    return 0;
}