【xsy1378】 水题7号 贪心

题目大意:有$m$组约束关系$(x_i,y_i)$,你要构造一个排列,满足数$x_i$出现在数$y_i$前面,请使得这个排列字典序最小,请输出这个排列。无解请输出-1。

数据范围:$n,m≤10^5$

 

我们把约束关系$(x_i,y_i)$视作从$y_i$连向$x_i$的有向边,于是我们得到了一个有向图,无解情况下该图会存在环。

我们对这个有向图进行拓扑排序即可,只不过每次出队的点是当前队列中编号最大的点。

我们开一个数组$ans$,记$ans_i$表示第i次出队的点的编号。

若原图中存在环,显然$|ans|≠n$,我们可以通过该性质判断是否有解。

否则倒着输出$ans$数组即可。

关于正确性可以这么理解:当第$x$个点出队时,所有依赖于该点的点都出队了,且当前编号大于它的点都出队了。

 

 1 #include<bits/stdc++.h>
 2 #define M 100005
 3 using namespace std;
 4 
 5 vector<int> v[M];
 6 int n,m,vis[M]={0};
 7 int ans[M]={0},in[M]={0},cnt=0;
 8 priority_queue<int> q;
 9 int Main(){
10     memset(in,0,sizeof(in));
11     memset(ans,0,sizeof(ans)); cnt=0;
12     for(int i=0;i<M;i++) v[i].clear();
13     scanf("%d%d",&n,&m);
14     for(int i=1;i<=m;i++){
15         int x,y; scanf("%d%d",&x,&y);
16         v[y].push_back(x); in[x]++;
17     }
18     for(int i=1;i<=n;i++) if(in[i]==0) q.push(i);
19     while(!q.empty()){
20         int u=q.top(); q.pop();
21         ans[++cnt]=u;
22         int siz=v[u].size();
23         for(int i=0;i<siz;i++){
24             int V=v[u][i];
25             in[V]--;
26             if(in[V]==0) q.push(V);
27         }
28     }
29     if(n!=cnt){
30         printf("Impossible!\n");
31         return 0;
32     }
33     for(int i=n;i;i--) printf("%d ",ans[i]);
34 }
35 int main(){
36     int t; cin>>t;
37     while(t--) Main();
38 }

 

 

posted @ 2019-03-05 18:35  AlphaInf  阅读(114)  评论(0编辑  收藏  举报