Poj 3687 Labeling Balls【逆向建图+拓扑排序+优先队列+思维】

Labeling Balls

Time Limit: 1000MS

 

Memory Limit: 65536K

Total Submissions: 13273

 

Accepted: 3830

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

Source

POJ Founder Monthly Contest – 2008.08.31, windy7926778

 

题目大意:有1-N编号的N个球 ,给出M个约束条件,表示球a比球b轻,输出每个球的重量。如果有多解情况,按照这样的条件输出:首先让1号球尽可能的轻,然后让2号球尽可能的轻,然后让3号球尽可能的轻.........................................


思路:

1、首先做图论题最重要的就是建图问题,如果正向建图解决问题比较复杂化,不妨多试一试逆向建图所带来的效果。

2、假设有这样一个反图(这里箭头3指向1,就变成了这样的含义:3比1重):


我们假设让先拓扑出来的节点的重量值更大的条件下(第一个拓扑出来的节点重量为n,第二个拓扑出来的点重量为n-1......):

显然3号是最先拓扑出来的节点,重量为最大,值为5,接下来是1和2,那么我们是要先进行1的拓扑还是2的拓扑呢?根据贪心思想,我们显然先处理2号节点,再处理1号节点,最后拓扑序为:

3 2 4 1 5

然后按照最初我们约定的规则来赋予每个节点重量值:

最后输出:

2 4 5 3 1.正解。

在这个过程中我们贪心的优先处理节点编号大的节点的问题,所以我们的队列可以搞成优先队列(节点编号大优先的优先队列)即可。


根据这个过程跑了一遍,发现能够输出正解,那么就按照这个过程写代码就行拉~。

综上所述,整体思路为:
1、反向建图,因为正向建图思路比较繁杂过程比较难以处理,尝试反向建图是否有优点存在。

2、反向建图之后模拟贪心过程发现能够输出正解,那么使用STL优先队列贪心搞即可。


AC代码:

#include<stdio.h>
#include<string.h>
#include<queue>
#include<vector>
using namespace std;
vector<int >mp[205];
int map[205][205];
int degree[205];
int ans[205];
int ans2[205];
int n,m;
void top()
{
    int cont=1;
    memset(ans,-1,sizeof(ans));
    priority_queue<int, vector<int>, less<int> > s;
    for(int i=1;i<=n;i++)
    {
        if(degree[i]==0)
        {
            s.push(i);
            degree[i]=-1;
        }
    }
    while(!s.empty())
    {
        int u=s.top();
        ans[cont++]=u;
        s.pop();
        for(int i=0;i<mp[u].size();i++)
        {
            int v=mp[u][i];
            degree[v]--;
            if(degree[v]==0)
            {
                degree[v]=-1;
                s.push(v);
            }
        }
    }
    if(cont!=n+1)
    {
        printf("-1\n");
        return ;
    }
    for(int i=1;i<=n;i++)
    {
        ans2[ans[i]]=cont-1;
        cont--;
    }
    for(int i=1;i<=n;i++)
    {
        printf("%d ",ans2[i]);
    }
    printf("\n");
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(degree,0,sizeof(degree));
        memset(map,0,sizeof(map));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)mp[i].clear();
        for(int i=0;i<m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            if(map[y][x]==0)
            {
                map[y][x]=1;
                mp[y].push_back(x);
                degree[x]++;
            }
        }
        top();
    }
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值