UESTC Training for Graph Theory——G、Labeling Balls

Labeling Balls

Time Limit: 1000 ms Memory Limit: 65536 kB Solved: 193 Tried: 859

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

Hint

The data used in this problem is unofficial data prepared by allenlowesy. So any mistake here does not imply mistake in the offcial judge data.

Source

POJ Founder Monthly Contest – 2008.08.31, win

/*算法思想:
  给标号为1...n的球分配重量,要求分配的重量组成的排列的康托展开尽可能小
  很容易想到是用拓扑排序,然后对每个标号分配重量,但是这道题最关键的是建图
  首先不能正向建图,即不能这样定义边的意义:x--->y:表示标号为 x 的球的重量比标号为 y 的球的重量小
  刚开始我就这样定义的,但是我出的第一组数据就把自己的代码cha挂了:
  <4,3>,<3,2>,<5,1>
  正向建图:4-->3-->2    5-->1
  这组数据的标准解应该是:2 5 4 3 1
  但是如果按照上面的建图方式得到的解却是:5 3 2 1 4,明显不是最优的
  因为要求的是输出的重量的康托展开最小,也就是说标号小的球的重量尽可能小,那么我们应该做的就是尽量
  先把大的重量分配出去,这样,我们才能够保证最后得到重量的序列的康托展开最小,而要先把大的重量分配出
  去我们就应该逆向建图,即这样定义边的意义:x--->y:表示标号为x的球的重量大于标号为y的球的重量。比如
  <4,3>,<3,2>,<5,1>
  逆向建图之后就应该是:1-->5    2-->3-->4
  这样,每次给一个球分配重量的时候我们总是找当前入度为0并且标号最大的点,把当前能分配的最大的重量分
  配给它。这样得出的解才是最优的
*/

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int ans[205];
bool g[205][205];
int in[205];  //统计入度
int n,m;
bool topo(int now)
{
    if(now==0)
    {
        for(int i=1;i<n;i++)
            printf("%d ",ans[i]);
        printf("%d\n",ans[n]);
        return true;
    }
    for(int i=n;i>0;i--)
        if(in[i]==0)
        {
            for(int j=n;j>0;j--)
                if(g[i][j])  in[j]--;
            ans[i]=now;
            in[i]=-1;
            if(topo(now-1)) return true;  //找到了直接返回true,不用再枚举下一个入度为0的点了
        }
    return false;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        int a,b;
        memset(in,0,sizeof(in));
        memset(ans,0,sizeof(ans));
        memset(g,0,sizeof(g));
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&a,&b);
            if(!g[b][a])
            {
                g[b][a]=true;
                in[a]++;
            }
        }
        if(!topo(n)) printf("-1\n");
    }
    return 0;
}


 

 

你可能感兴趣的:(UESTC Training for Graph Theory——G、Labeling Balls)