POJ3687Labeling Balls 解题思路加感受

来源:互联网 发布:ssh连接阿里云 编辑:程序博客网 时间:2024/06/16 09:13
Labeling Balls
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 12767 Accepted: 3672

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

54 04 11 14 21 22 14 12 14 13 2

Sample Output

1 2 3 4-1-12 1 3 41 3 2 4

Source


题目大意:首先对N个质量分别为1,2,~N的球进行编号为1,2,~N,然后对某些编号的球的质量会有要求,比如:3  2,这就要求序号为3的球的质量必须小于序号为2的球,在这样的要求下可能会有多种排序方式,但没有涉及的一些球之间也要满足序号小的球的质量要小于序号大的球的质量,比如上面第五个样例中给出的 n=4,m=1,3  2 代表序号为3的球的质量要小于序号为2的球,最终答案时1  3  2  4,而不是3  2  1  4或者 2   4   3  1 等等,,此道题目利用拓扑进行逆序建图会方便不少。 

上代码:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<stack>
using namespace std;
int map[210][210],in[210],out[210],vis[210];
int n,m;
int tp[210];
int topo()
{
    stack<int >s;
    int num,num1,i,j;
    for(i=1,num=0; i<=n; i++)                                // 该for循环最后得到有要求的点的数目
    {
        if(vis[i]==1)
        {
            num++;
        }
    }
    num1=0;
    for(i=1;i<=n;i++)                                             //开始判断有木有环       在这里额wa了n次
    {
        if(vis[i]==1&&in[i]==0)   s.push(i);           
    }
    while(!s.empty())
    {
        int x=s.top();
        s.pop();
        num1++;
        for(i=1;i<=n;i++)
        {
            if(map[x][i])
            {
                in[i]--;
                if(in[i]==0)
                    s.push(i);
            }
        }
    }
    if(num1!=num)                           //有环输出-1
    {
        printf("-1\n");
        return 0;
    }
    num=n;
    memset(tp,0,sizeof(tp));
    while(1)
    {
        for(i=n; i>0; i--)
        {
            if(tp[i]==0&&out[i]==0)                  //依据编号从大到小进行安排
                break;
        }
        if(i==0) break;
        tp[i]=num--;
        for(j=1; j<=n; j++)
        {
            if(map[j][i]==1)
                out[j]--;
        }
    }
    for(i=1; i<=n; i++)
    {
        if(i!=n) printf("%d ",tp[i]);
        else  printf("%d\n",tp[i]);
    }
    return 0;
}
int main()
{
    int T,s,e,i;
    scanf("%d",&T);
    while(T--)
    {
        memset(map,0,sizeof(map));
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        memset(vis,0,sizeof(vis));
        scanf("%d %d",&n,&m);
        if(m==0)
        {
            for(i=1; i<=n; i++)
            {
                if(i!=n)
                    printf("%d ",i);
                else printf("%d\n",i);
            }
        }
        else
        {
            for(i=1; i<=m; i++)
            {
                scanf("%d %d",&s,&e);
                if(map[s][e]==0)                                     //记得要判断重边
                {
                    map[s][e]=1;
                    in[e]++;
                    out[s]++;
                    vis[s]=vis[e]=1;                                      //对有要求的点做个记号
                }
            }
            topo();                //here  we  go  topo
        }
    }
    return 0;
}


1 0