POJ 3687 Labeling Balls
拓扑排序
传送门:POJ
传送门:HustOJ
题意
这道题每次输入a,b的时候表示的是编号为a的球比编号为b的球轻,最后输出的是从编号 1 到编号 n每个小球的重量,如果存在多组解,输出使最小重量尽量排在前边的那组解,亦即 所有解中 1到 n号球的重量的字典序最小。
思路
逆向拓扑排序。
%%%感觉讲的比较详细。
给一组数据理解一下反向拓扑排序的必要性:4号轻于1号,3号轻于2号。
如果按照普通的拓扑排序,建图时4–>1,3–>2。从入度为0的点里面选编号最小的,输出,会得到:4213。即1号球重量4。
但是从另一个角度想,既然要求1号球重量最小,而只有4号球比他轻,那么理论上1号球重量可以达到2。所以正向拓扑排序不行。
我们反向建图,然后将入度为0的入队,每次从队列里面选择编号最大的,给他一个大重量,这样保证最后才将编号小的出队,得到一个小重量。
另外注意判断一下环就行了。
代码
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#define _ ios_base::sync_with_stdio(0),cin.tie(0)
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=305;
const int oo=0x3f3f3f3f;
typedef long long LL;
const LL loo=4223372036854775807ll;
typedef long double LB;
const LL mod=1e9+7;
vector<int> G[MAXN];
int indegree[MAXN];
int topsort[MAXN];
int main()
{
_;
int T;cin>>T;
while(T--)
{
int n, m;cin>>n>>m;
for(int i=0;i<MAXN;i++) G[i].clear();
M(indegree, 0);M(topsort, 0);
int top=n;
while(m--)
{
int a, b;cin>>a>>b;
G[b].push_back(a);//a比b轻
indegree[a]++;
}
priority_queue<int> Q;
bool flag=0;
for(int i=1;i<=n;i++)
{
if(indegree[i]==0) Q.push(i);
}
if(Q.empty()) flag=1;
else
{
while(!Q.empty())
{
int tp=Q.top();Q.pop();
topsort[tp]=top--;
for(int i=0;i<G[tp].size();i++)
{
indegree[G[tp][i]]--;
if(indegree[G[tp][i]]==0)
{
Q.push(G[tp][i]);
}
}
}
}
if(top!=0||flag==1) cout<<-1<<endl;
else
{
for(int i=1;i<=n;i++)
{
cout<<topsort[i]<<(i==n ? '\n' : ' ');
}
}
}
return 0;
}