题目链接
题意 给出两个数n和m
再给出m个大小关系二元组[u,v] u必须在v前面
求满足要求得n个数的全排列,输出每个数对应的下标。 如果有多解 要求输出字典序最小。
解题思路: 本题输出要求输出字典序最小的解,则首先考虑贪心思想。
一开始很容易想到用优先队列求出储存入度为零的点,这样子这样子来贪心求解。
#include <bits/stdc++.h>
using namespace std;
const int MAX=100000+10;
int du[MAX];
vector<int> G[MAX];
int a[MAX];
int main(){
int n,m;
scanf("%d %d",&n,&m);
for(int i=0;i<m;i++){
int u,v;
scanf("%d %d",&u,&v);
G[u].push_back(v);
du[v]++;
}
priority_queue<int> PQ;
for(int i=1;i<=n;i++){
if(!du[i]) PQ.push(-i);
}
vector<int> ans;
while(!PQ.empty()){
int now=-PQ.top();PQ.pop();
for(int i=0;i<G[now].size();i++){
int v=G[now][i];
du[v]--;
if(!du[v]) PQ.push(-v);
}
ans.push_back(now);
}
for(int i=0;i<ans.size();i++){
a[ans[i]]=i+1;
}
for(int i=1;i<=n;i++){
cout<<a[i]<<" ";
}
puts("");
}
然后wa到怀疑人生。 因为这样子求解,是使得拓扑序字典序最小,而不是他们的对应的序号字典序最小。
如果要这么顺序求解序号字典序最小的话,每次决策都会有后效性, 显然不能这么做。
既然要消除后效性,那么就可以逆序贪心求解,把题目所给出的大小关系转向,然后逆序求解就可以消除后效性了。
#include <bits/stdc++.h>
using namespace std;
const int MAX=100000+10;
int du[MAX];
vector<int> G[MAX];
int a[MAX];
int vis[MAX];
int main() {
int n,m;
scanf("%d %d",&n,&m);
for(int i=0; i<m; i++) {
int u,v;
scanf("%d %d",&u,&v);
G[v].push_back(u);
du[u]++;
vis[u]=vis[v]=1;
}
priority_queue<int> PQ;
for(int i=1; i<=n; i++) {
if(!du[i]) {
PQ.push(i);
}
}
vector<int> ans;
int j=n;
while(!PQ.empty()) {
int now=PQ.top();
a[now]=j--;
PQ.pop();
for(int i=0; i<G[now].size(); i++) {
int v=G[now][i];
du[v]--;
if(!du[v]) PQ.push(v);
}
}
for(int i=1; i<=n; i++) {
if(a[i]==0)
cout<<i<<" ";
else
cout<<a[i]<<" ";
}
puts("");
}