题目描述
Windy has N balls of distinct weights from 1 unit to N units. Now he tries to label them with 1 to N in such a way that:
No two balls share the same label.
The labeling satisfies several constrains like “The ball labeled with a is lighter than the one labeled with b”.
Can you help windy to find a solution?
算法思路
- 纯粹为了输出字典序想了很长时间,WA了很多次,最后终于想通了。
- 其实使用堆的算法可以看作一个贪心算法,因为每次取的元素都是当前最优先的元素,所以着重要看它们的最优子结构和贪心选择的性质。
- 如果我们正向拓扑,那么显然我们期望越小的标号被越早的选中,所以我们会用小顶堆,但是,此时不一定可以得到字典序,因为如果一个很大的元素在1的前面,就可以造成错误。
- 所以,我们逆向拓扑,构造大顶堆,此时我们期望标号越小的点被越晚的选中,很显然此时可以成立。
- 还有,图中会有重边,注意判断。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
#define MAXN 203
#define INF 0x3f3f3f3f
int n,m,t;
int grid[MAXN][MAXN];
int indeg[MAXN];
void Solve()
{
int i;
int a[MAXN];
int ans[MAXN];
int Count = 0;
priority_queue<int,vector<int>,less<int> >Q;
for(i=1;i<=n;i++){
if(!indeg[i]){
Q.push(i);
indeg[i] = -1;
}
}
while(!Q.empty()){
int cur = Q.top();
Q.pop();
a[++Count]=cur;
for(i=1;i<=n;i++){
if(grid[cur][i]){
indeg[i]--;
if(!indeg[i]){
indeg[i] = -1;
Q.push(i);
}
}
}
}
if(Count<n)
printf("-1\n");
else{
for(i=1;i<=n;i++)
ans[a[n-i+1]]=i;
printf("%d",ans[1]);
for(i=2;i<=n;i++)
printf(" %d",ans[i]);
printf("\n");
}
return;
}
int main()
{
freopen("input","r",stdin);
int i,tmp1,tmp2;
scanf("%d",&t);
while(t--){
memset(indeg,0,sizeof(indeg));
memset(grid,0,sizeof(grid));
scanf("%d%d",&n,&m);
for(i=0;i<m;i++){
scanf("%d%d",&tmp1,&tmp2);
if(!grid[tmp2][tmp1]){
grid[tmp2][tmp1]=1;
indeg[tmp1]++;
}
}
Solve();
}
return 0;
}