题意:给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; }