Poj 3687 -- Labeling Balls

本文探讨了一种使用拓扑排序算法解决球权重排列问题的方法,包括问题描述、输入输出格式、实现思路及代码实现。通过实例演示了如何通过拓扑排序找到满足特定约束条件的球权重排列,提供了详细的解析步骤和代码实现。
Labeling Balls
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 9070 Accepted: 2451

Description

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:

  1. No two balls share the same label.
  2. 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?

Input

The first line of input is the number of test case. The first line of each test case contains two integers, N (1 ≤ N ≤ 200) and M (0 ≤ M ≤ 40,000). The next M line each contain two integers a and b indicating the ball labeled with a must be lighter than the one labeled with b. (1 ≤ a, b ≤ N) There is a blank line before each test case.

Output

For each test case output on a single line the balls' weights from label 1 to label N. If several solutions exist, you should output the one with the smallest weight for label 1, then with the smallest weight for label 2, then with the smallest weight for label 3 and so on... If no solution exists, output -1 instead.

Sample Input

5

4 0

4 1
1 1

4 2
1 2
2 1

4 1
2 1

4 1
3 2

Sample Output

1 2 3 4
-1
-1
2 1 3 4
1 3 2 4


思路:这是一道很有意思的题。由于今天刚接触拓扑排序,所以做这个题感觉非常非常吃力。之所以说他有意思,是因为这个题灵活性很大,
除了要逆向建图,还需要注意很多地方,比如说输出的是球的重量和重边问题等等。可以举个例子来说明我的思路:
5 4
5 1
4 2
1 3
2 3
给出这组数据:用一数组标记是否重边,且用数组建立数与数之间的联系。比如输入a,b拿后面两对 1 3\n 2 3,可以令s[1][3]=1.s[2][3]=1
这样不仅可以标记已经存在,还可以说明3 与1 2存在关系。然后in[a]++, in[]表示入度。
然后就可以建图了。不断寻找入度为零的数加进优先队列,每出一个元素,与它有联系的元素的入度均减一,出去的这个元素重量肯定是最大的,然后再找入度为零的元素进队列
再出队列。此元素(即球的标号)的重量是第二大的。不断进出直到队列为空。

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <queue>
 5 using namespace std;
 6 int in[250],s[250][250],weight[250];
 7 void slove(int n)
 8 {
 9     priority_queue<int>que;
10     int i,g=n;
11     for(int i=1; i<=n; i++){
12         if(in[i]==0) que.push(i);
13     }
14     while(!que.empty()){
15         int t=que.top();
16         weight[t]=g--;
17         que.pop();
18         for(int i=1; i<=n; i++){
19             if(s[t][i] && --in[i]==0){
20                 que.push(i);
21             }
22         }
23     }
24     for(i=1; i<=n; i++){
25         if(!weight[i]){
26             printf("-1\n");
27             break;
28         }
29     }
30     if(i<=n) return ;
31     int flag=0;
32     for(int i=1; i<=n; i++){
33         if(flag) printf(" ");
34         printf("%d",weight[i]);
35         flag=1;
36     }
37     printf("\n");
38 }
39 int main()
40 {
41     int cas,n,m,a,b;
42     scanf("%d",&cas);
43     while(cas--){
44         memset(s,0,sizeof(s));
45         memset(in,0,sizeof(in));
46         memset(weight,0,sizeof(weight));
47         scanf("%d%d",&n,&m);
48         for(int i=0; i<m; i++){
49             scanf("%d%d",&a,&b);
50             if(!s[b][a]){
51                 s[b][a]=1;
52                 in[a]++;
53             }
54         }
55         slove(n);
56     }
57     return 0;
58 }

 






转载于:https://www.cnblogs.com/ubuntu-kevin/p/3226475.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值