POJ 3687 Labeling Balls

32 篇文章 0 订阅
12 篇文章 0 订阅

POJ 3687 Labeling Balls

拓扑排序

传送门:POJ

传送门:HustOJ


题意

这道题每次输入a,b的时候表示的是编号为a的球比编号为b的球轻,最后输出的是从编号 1 到编号 n每个小球的重量,如果存在多组解,输出使最小重量尽量排在前边的那组解,亦即 所有解中 1到 n号球的重量的字典序最小。


思路

逆向拓扑排序。

%%%感觉讲的比较详细。

给一组数据理解一下反向拓扑排序的必要性:4号轻于1号,3号轻于2号。

如果按照普通的拓扑排序,建图时4–>1,3–>2。从入度为0的点里面选编号最小的,输出,会得到:4213。即1号球重量4。

但是从另一个角度想,既然要求1号球重量最小,而只有4号球比他轻,那么理论上1号球重量可以达到2。所以正向拓扑排序不行。

我们反向建图,然后将入度为0的入队,每次从队列里面选择编号最大的,给他一个大重量,这样保证最后才将编号小的出队,得到一个小重量。

另外注意判断一下环就行了。


代码

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>

#define _ ios_base::sync_with_stdio(0),cin.tie(0)
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;

const int MAXN=305;
const int oo=0x3f3f3f3f;
typedef long long LL;
const LL loo=4223372036854775807ll;
typedef long double LB;
const LL mod=1e9+7;

vector<int> G[MAXN];
int indegree[MAXN];
int topsort[MAXN];
int main()
{
    _;
    int T;cin>>T;
    while(T--)
    {
        int n, m;cin>>n>>m;
        for(int i=0;i<MAXN;i++) G[i].clear();
        M(indegree, 0);M(topsort, 0);
        int top=n;

        while(m--)
        {
            int a, b;cin>>a>>b;
            G[b].push_back(a);//a比b轻
            indegree[a]++;
        }

        priority_queue<int> Q;
        bool flag=0;
        for(int i=1;i<=n;i++)
        {
            if(indegree[i]==0) Q.push(i);
        }
        if(Q.empty()) flag=1;
        else
        {
            while(!Q.empty())
            {
                int tp=Q.top();Q.pop();
                topsort[tp]=top--;
                for(int i=0;i<G[tp].size();i++)
                {
                    indegree[G[tp][i]]--;
                    if(indegree[G[tp][i]]==0)
                    {
                        Q.push(G[tp][i]);
                    }
                }
            }
        }
        if(top!=0||flag==1) cout<<-1<<endl;
        else
        {
            for(int i=1;i<=n;i++)
            {
                cout<<topsort[i]<<(i==n ? '\n' : ' ');
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值