POJ 3687 Labeling Balls(拓扑排序+反向思考)

87 篇文章 0 订阅
20 篇文章 0 订阅
Labeling Balls
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 13776 Accepted: 3983

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 integers a and b indicating the ball labeled witha 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 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

题目大意:
    有N个重量不一样的球,重量为1~N,有N个盒子,标号为1~N,给出M组大小关系,a b表示标号为a的盒子放的球比标号为b的盒子放的球轻。从左到右输出每个盒子里的球的重量,而且前面的盒子里的球要尽可能的小。(注意是按照盒子的顺序输入里面的球,不是输出各个球所在的盒子!!!不知道自己WA哪的同学好好读一下题)

解题思路:
    这题确实题意杀,思维有点绕,开始读错题了WA了好几发。
    我们每个盒子之间的约束条件,如果直接拓扑排序得到的是怎么摆放盒子,使它们内部的球为1~N,然而这并不是题目问的。
    由于要求字典序最小,我们要让第一个盒子装尽可能轻的球,然而根据题目条件给盒子找球并不好实现。所以我们可以从相反的角度思考一下:我们只要让重的球尽可能放在后面就可以保证字典序最小,这样就转化成了给球找盒子,直接贪心地拓扑排序即可。

AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

const int maxn=200+3;
int N,M;
bool used[maxn];//是否每个盒子是否已经放球的
vector<int> G[maxn];//入边表
int out[maxn],ans[maxn];

bool toposort()
{
    for(int i=N;i>0;--i)//先分配重的球
    {
        int select=-1;
        for(int j=N;j>0;--j)//优先放右边的盒子
            if(!used[j]&&!out[j])
            {
                select=j;
                break;
            }
        if(select==-1)//存在环,无解
            return false;
        for(int j=0;j<G[select].size();++j)
            --out[G[select][j]];
        used[select]=true;
        ans[select]=i;
    }
    return true;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(used,0,sizeof used);
        memset(out,0,sizeof out);
        scanf("%d%d",&N,&M);
        for(int i=1;i<=N;++i)
            G[i].clear();
        for(int i=0;i<M;++i)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            G[b].push_back(a);//入边表
            ++out[a];
        }
        if(toposort())
            for(int i=1;i<=N;++i)
                printf("%d%c",ans[i],i==N?'\n':' ');
        else puts("-1");
    }
    
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值