题意: N个球,从1~N编号,质量各不相同,给出小球间的质量关系(如给出a b 表示 a比b轻), 要求给每个球贴标签(此标签表示该小球为第几轻)。按编号输出每个球的标签。如果解不唯一,标签小的应该先分配给编号小的.(即取字典序最小的结果)
分析: 通过以下这组数据分析:
1
5 4
1 4
4 2
5 3
3 2
建图: a->b表示编号为a的球重量<编号为b的球, 以下为正向建立拓扑图
模拟拓扑排序选择如下:
1. 当前要贴标签1, 可取出的小球编号为1, 5, 解不唯一,标签小的应该先分配给编号小的., 故取出1. 并给编号1的小球分配标签1;
2. 当前要贴标签2, 可取出的小球编号为4, 5, 解不唯一,标签小的应该先分配给编号小的., 故取出4. 并给编号4的小球分配标签2;
3. 当前要贴标签3, 可取出的小球编号为5, 解唯一, 故取出5, 给编号为5的小球分配标签3。
依次类推, 分别给编号为3的小球分配标签4, 给编号为2的小球分配标签5.
故结果为:
小球编号: 1 2 3 4 5
相应标签: 1 5 4 2 3 (输出结果)
正确结果: 1 5 3 4 2 (这个结果是由先取编号1的小球, 再取编号5的小球, 再取编号3的小球, 再取编号4的小球, 最后取编号2的小球得出的)
明显15342字典序<15423. 故正向拓扑结果不能成立。
这个时候我们可以换个思路,逆向拓扑, 并且每次都先分配大标签, 并且将编号大的小球先取出, 这样就可以标签小的就可以分配给编号小的小球了.
具体过程不详述, 请看code:
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int maxn = 205;
int n,m;
int e[maxn][maxn], d[maxn], num[maxn];
int main()
{
int T, i, j, k;
//freopen("in.txt", "r", stdin);
scanf("%d", &T);
while(T--){
memset(e, 0, sizeof(e));
memset(d, 0, sizeof(d));
int a, b;
scanf("%d %d", &n, &m);
for(i=1; i<=m; i++){
scanf("%d %d", &a , &b);
if(!e[b][a]){//反向建图
e[b][a] = 1;//连接
d[a]++;//度
}
}
/********solve***********/
bool flag=false;
for(i=n; i>=1; i--){//从最大的标签开始贴
for(j=n; j>=1; j--){//取当前未被分配标签的小球中编号最大的小球
if(!d[j]){
num[j]=i;//当前为选出的编号为j的小球分配标签i
d[j]--;
for(k=1;k<=n;k++){
if(e[j][k]){
d[k]--;
}
}
break;
}
}
if(j==0){
flag=true;
}
}
if(!flag){
for(i=1; i<=n; i++){
if(i!=1) printf(" ");;
printf("%d", num[i]);
}
printf("\n");
} else{
printf("-1\n");
}
}
return 0;
}