POJ 3687-Labeling Balls(反向拓扑排序)

Labeling Balls

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 16050 Accepted: 4717

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, 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 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

Source

POJ Founder Monthly Contest – 2008.08.31, windy7926778

题目大意:给你n个球编号为1~n,和m个条件x y满足编号为x的球比编号为y的球轻,让你给每个编号的球赋一个重量,满足前面的条件,若有多种答案输出1~n编号球的重量的字典序最小的。没有答案输出“-1”。

解题思路:很容易想到拓扑排序,方法没错,但是这道题需要建反向图再进行拓扑排序,这样的结果才会是最优的,有的贪心的策略,例如有两个条件:4 1 和 2 3

大家想到正向的策略肯定是,编号小的先出队,重量从小的开始赋,反向的策略就是与正向相反。

如果采用正向拓扑排序的策略的话,那么出队的顺序是 2 3 4 1,那么球的重量为w[2] = 1,w[3] = 2,w[4] = 3,w[1] = 4,这样的结果为4 1 2 3

然而采用反向拓扑排序的策略的话,那么出队的顺序为 3 2 1 4,那么球的重量为w[3] = 4,w[2] = 3,w[1] = 2,w[4] = 1,这样的结果为2 3 4 1

显然反向策略字典序最小,为什么呢,因为要按编号字典序最小,如果我们正向拓扑排序的话,会把小的重量用掉了,这样就会导致,可能你把小重量用到了编号大的球上,后面编号小的却用了一个大的重量,所以不一定使得字典序最小,就如同上面那个例子,但是反着来就不一样了,因为我们每次出队编号大的,并且给他赋值重量大的,这样的结果会使得字典序最小。

还有一个坑点:有重边!!!

AC代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<math.h>
#include<cstdlib>
#include<stdlib.h>
#include<queue>
#include<map>
#include<set>
#include<stack>
#define bug printf("*********\n");
#define mem0(a) memset(a, 0, sizeof(a));
#define mem1(a) memset(a, -1, sizeof(a));
#define finf(a, n) fill(a, a+n, INF);
#define in1(a) scanf("%d" ,&a);
#define in2(a, b) scanf("%d%d", &a, &b);
#define in3(a, b, c) scanf("%d%d%d", &a, &b, &c);
#define out1(a) printf("%d\n", a);
#define out2(a, b) printf("%d %d\n", a, b);
#define pb(G, b) G.push_back(b);
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef pair<LL, pair<int, LL> > LLppar;
typedef pair<int, int> par;
typedef pair<LL, int> LLpar;
const LL mod = 1e9+7;
const int INF = 1e9+7;
const int N = 1010;
const double pi = 3.1415926;

using namespace std;

int n, m, cnt;
int head[210];
int in[210], out[210], a[210];
int vis[210][210];

struct edge
{
    int to;
    int next;
}e[40010];

void add(int u, int v)
{
    e[cnt].to = v;
    e[cnt].next = head[u];
    head[u] = cnt ++;
}

int ans[210];

bool topo()
{
    priority_queue<int> q;
    int sum = 0, k = n;
    for(int i = 1; i <= n; i ++) {
        if(in[i] == 0) {
            q.push(i);
        }
    }
    while(!q.empty()) {
        int u = q.top();
        q.pop();
        sum ++;
        ans[u] = k --;
        for(int i = head[u]; ~i; i = e[i].next) {
            int en = e[i].to;
            in[en] --;
            if(in[en] == 0) {
                q.push(en);
            }
        }
    }
    if(sum != n) printf("-1\n");
    else {
        for(int i = 1; i <= n-1; i ++) {
            printf("%d ", ans[i]);
        }
        printf("%d\n", ans[n]);
    }
}

void inti()
{
    mem1(head);
    mem0(in);
    mem0(out);
    mem0(vis);
    cnt = 0;
}

int main(int argc, char * argv[])
{
    int x, y, z, T;
    scanf("%d", &T);
    while(T --) {
        scanf("%d%d", &n, &m);
        inti();
        for(int i = 0; i < m; i ++) {
            scanf("%d%d", &x, &y);
            if(!vis[x][y]) { //有重边
                vis[x][y] = 1;
                add(y, x);
                in[x] ++;
                out[y] ++;
            }
        }
        topo();
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值