POJ 3687 Labeling Balls 【逆拓扑】

本文介绍了一种使用拓扑排序和优先队列解决标签分配问题的方法,具体步骤包括输入数据预处理、构建依赖关系矩阵、进行拓扑排序并输出符合约束条件的标签权重序列。在遇到多重解时,通过特定规则选择最优解。实例分析展示了算法在特定输入条件下的应用,以及如何处理无解的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Labeling Balls

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 12304 Accepted: 3527

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

 

嗯,题目大意就是说,n个气球重量为1到n,现在要贴标签也是1到n,然后下面是m个要求例如a b,表示标号为a的球要比标号为b的球轻,然后输出的是从1号到n号所对应的球的重量。拓扑排序时要求当排序不唯一时要让标号小的重量也小,这里我用逆拓扑和优先队列,正常情况让输出所排的标签的顺序时要逆序输出,这里我是先让数组反转,之后在通过标号找重量,按标号从小到大输出重量。嗯,我做的比较麻烦,不造别人怎么做的。。。。

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int n,in[220],ans[220],rec[220],map[220][220];
void top_sort()
{
    int k=0;
    priority_queue<int>q;
    for(int i=1;i<=n;++i)
    {
        if(in[i]==0)
        {
            q.push(i);
            in[i]--;
        }
    }
    while(!q.empty())
    {
        int u=q.top();
        rec[k++]=u;
        q.pop();
        for(int i=1;i<=n;++i)
        {
            if(map[u][i])
            {
                in[i]--;
                if(in[i]==0)
                {
                    q.push(i);
                    in[i]--;
                }
            }
        }
    }
    if(k<n)
        printf("-1\n");
    else
    {
        int i,j;
        for(i=k-1,j=0;i>=0;i--)
            ans[++j]=rec[i];
        /*memset(rec,0,sizeof(rec));
        for(i=1;i<=k;++i)//这里找到与原先数组刚好那什么的数组再输出,嗯,就是例如a[2]=4,那么我所找的数组就是b[4]=2
            rec[ans[i]]=i;
        for(int i=1;i<=k;++i)
        {
            if(i==1)
                printf("%d",rec[i]);
            else
                printf(" %d",rec[i]);
        }*/
        for(i=1;i<=k;++i)//这里直接按标号找重量
        {
            for(j=1;j<=k;++j)
            {
                if(ans[j]==i)
                {
                    if(i==1)
                        printf("%d",j);
                    else
                        printf(" %d",j);
                    break;
                }
            }
        }
        printf("\n");
    }
}
int main()
{
    int t,m,a,b;
    scanf("%d",&t);
    while(t--)
    {
        memset(in,0,sizeof(in));
        memset(map,0,sizeof(map));
        scanf("%d%d",&n,&m);
        while(m--)
        {
            scanf("%d%d",&a,&b);
            if(!map[b][a])
            {
                map[b][a]=1;
                in[a]++;
            }
        }
        top_sort();
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值