您的位置:首页 > 其它

贴标签

2016-08-24 09:20 225 查看
罗老师正在给一堆球贴标签,总共有N个球,要给他们贴1-N的编号,不能重复。

罗老师首先将这N个球排成一排,排好后,突然想给自己找点麻烦(无聊),就想出了M条限制条件,每个条件是:

A B

表示第A个球的编号要小于第B个球的编号。

当然,限制条件会造成有时答案有很多种,那么罗老师希望贴好标签后的球字典序最小;也有可能答案不存在,那么就输出-1。

输入

首先输入T,表示有T组测试数据

然后每组测试数据首先输入N, M

接下来M行每行输入A B,表示第A个球编号要小于第B个球

输出

如果答案存在,输出最小字典序(数字字典序,也就是优先小数字在前,比如 22 在 111前)不存在就输出”-1”

样例输入

5

4 0

4 1

1 1

4 2

1 2

2 1

4 1

2 1

4 1

3 2

样例输出

1 2 3 4

-1

-1

2 1 3 4

1 3 2 4

提示

【数据规模和约定】

1<=N<=200 0<=M<=40000 可能有重边

题意:n个重量为1−n的球,给定一些编号间的重量比较关系,现在给每个球编号,在符合条件的前提下使得编号小的球重量小。(先保证1号球最轻,其次2号……)

分析:拓扑排序,注意根据题的要求,要先保证1号球最轻,如果我们由轻的向重的连边,然后我们依次有小到大每次把重量分给一个入度为0的点,那么在拓扑时我们面对多个入度为0的点,我们不知道该把最轻的分给谁才能以最快的速度找到1号(使1号入度为0),并把当前最轻的分给1号。所以我们要由重的向轻的连边,然后从大到小每次把一个重量分给一个入度为0的点。这样我们就不用急于探求最小号。我们只需要一直给最大号附最大值,尽量不给小号赋值,这样自然而然就会把轻的重量留给小号。

注意重边。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
int t,n,m,x,y,tot;
int p[205][205],a[205][205],c[205],ru[205];
int head[205],Next[40005],to[40005];
void add(int x,int y)
{
tot++;
Next[tot]=head[x];
to[tot]=y;
head[x]=tot;
}
void tuopu()
{
int w=n;
while(1)
{
int t=0,find=0;
for(int i=n;i>=1;i--)
if(ru[i]==0)
{
find=1;
c[i]=w;
w--;
ru[i]--;
for(int j=head[i];j!=-1;j=Next[j]) ru[to[j]]--;
break;
}
if(!find) break;
}
for(int i=1;i<n;i++) printf("%d ",c[i]);
printf("%d\n",c
);
}
int floyd()
{
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i][k]&&a[k][j]) a[i][j]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i][j]&&a[j][i]) return -1;
return 0;
}
int main()
{
cin>>t;
while(t--)
{
cin>>n>>m;
tot=0;
memset(p,0,sizeof(p));
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)
{
head[i]=-1;
ru[i]=0;
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
if(p[y][x]==0)
{
add(y,x);
ru[x]++;
}
p[y][x]=1;
a[y][x]=1;
}
if(floyd()==-1) printf("-1\n"); else tuopu();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: