poj 3687 拓扑排序 - 反向建图


 

Labeling Balls
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 9385 Accepted: 2549

Description

Windy has N balls of distinct weights from 1 unit to N units. Now he tries to label them with 1 toN 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 withb".

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 nextM line each contain two integersa and b indicating the ball labeled witha must be lighter than the one labeled withb. (1 ≤ a, bN) 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 labelN. 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

Source

POJ Founder Monthly Contest – 2008.08.31, windy7926778


这道题目需要认真读题。
题目需要求出的是 编号1-n的球的重量值。而且要求那个字典序最小的。
我们用拓扑排序的算法,需要让编号小的球尽可能往前排(获得较小的weight)。
但是如果每一步都去贪心,则会wa。因为 1<3 4 < 2 这种情况,会贪心出 1, 3, 4, 2 这个非最优解。(最优解应该是1,4,2,3)。因为当前贪心最小的球,并不能保证全局最小的球往前排。
因为1342对应的答案是1423 , 而 1423对应的答案是1324。这里是一个陷阱。所以需要认真读题。

因此我们反过来建图,每一步都选编号最大的那个求放到最后。(因此改用stack数据结构)

提交记录:
1. WA   因为没有看到题目中求的是 编号从1-n的球的重量!!! 需要做一个转化
2. WA   因为没有考虑到贪心的错误。需要 反向建图
3. AC
#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
         #include 
        
          #include 
         
           #define MAXN 210 using namespace std; int n, m; int graph[MAXN][MAXN]; stack 
          
            result_q; int judge() { int graph1[MAXN][MAXN]; memcpy(graph1, graph, sizeof(graph)); int i, j; int out[MAXN] = {0}; for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { if (graph1[i][j] == 1) { out[i] ++; } } } int k; stack 
           
             q; int flag = 0; for (k = 0; k < n; ) { queue 
            
              du; for (i = n-1; i >= 0; i--) { if (out[i] == 0) { du.push(i); } } if (du.size() == 0) return 2; //没有找到入度为0的点,说明有环。高优先级判断 while (!du.empty()) { i = du.front(); du.pop(); k++; q.push(i); for (int j = 0; j < n; j++) { if (graph1[j][i]) { out[j]--; //减少指向它的结点的入度 graph1[j][i] = 0; //删除指向它的边 } } out[i] = -1; break; } } result_q = q; return 1; } int main() { int t; cin >> t; while (t--) { cin >> n >> m; int i, j; int left, right; memset(graph, 0, sizeof(graph)); int flag = 0; for (i = 1; i <= m; i++) { cin >> left >> right; graph[left-1][right-1] = 1; } flag = judge(); if (flag == 1) { int o = 0; int w = 1; int record[MAXN] = {0}; while (!result_q.empty()) { int a = result_q.top(); result_q.pop(); record[a] = w; w++; } for (i = 0; i < n; i++) { if (o != 0) cout << " "; o = 1; cout << (record[i]); } cout << endl; } else if (flag == 2) { cout << -1 << endl; } } return 0; } 
             
            
           
          
         
       
      
      
     
     
    
    
   
   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值