巡回賽
時間限制:1000 ms | 內存限制:65535 KB
難度:3
描述
世界拳擊協會(WBA)是歷史最悠久的世界性拳擊組織,孕育了眾多的世界冠軍,尤其是重量級,幾乎造就了大家耳熟能詳的所有偉大的拳王。阿裡、弗雷澤、福爾曼被稱為“70年代重量級拳壇 三巨頭”,是當之無愧的拳王,他們的得到的金腰帶都刻有 WBA 字樣。為慶賀世界拳擊協會成立 50 周年,WBA 主席門多薩邀請 N 名拳擊手進行了 M 場巡回比賽,每場比賽均可分出勝負,比賽過後組委會要對 N 名選手進行排序,對於每名拳手,必須滿足該拳手所戰勝過的對手全部排在其後才能對該排名滿意。
現給出 M 場比賽的勝負關系,請你幫組委會決定是否能夠唯一確定這樣的排名,使得所有的拳擊手都滿意,若能唯一確定則輸出最終排名。
輸入
第一行給出測試數據的組數 T(0<T<30),對於每組測試數據,首先依次給出N(1<=N<=26),M(0<=M<=1000)分別表示拳手數和比賽數,拳手的姓名依次為從 A開始的前 N 個大寫字母,接下 M 行給出每場比賽的比賽結果,每行由兩個大寫字母組成,兩者之間有一空格。
如 “A B”則表示在某場比賽中 A 戰勝了 B。
輸出
對於每組測試,若不存在唯一的排名序列則單行輸出“No Answer”,若存在則按排名從高至低輸出拳手的名字。
樣例輸入
3
4 4
A B
A C
B C
C D
4 4
A B
A C
B D
C D
3 3
A B
B A
A C
樣例輸出
ABCD
No Answer
No Answer解題思路:先找到一個入度為0的點,從這個點開始找下一個入度為0的點,直到把所有的點都找完;在找的過程中,如果同時有多個或0個入度為0的點(最後一個點除外),則不存在拓撲排序。
#include<stdio.h>
#include<string.h>
int map[30][30],b[50],n,m,in[50];
char c[100];
void toposort()
{
int incnt=0,flag=1,front=1,rear=1,i,j,k;
for(i=1;i<=n;i++)
if(!in[i])
{
incnt++;
b[rear++]=i; /*找第一個入度為0的點*/
}
if(incnt!=1)
flag=0;
j=0; /*記錄保存的點的個數*/
while(front<rear)
{
incnt=0;
k=b[front++];
c[j++]=k+'A'-1; /*保存排好序的點*/
for(i=1;i<=n;i++) /*注意是n個點,不要寫成m*/
{
if(map[k][i])
{
in[i]--;
if(!in[i])
{
incnt++;
b[rear++]=i;/*如果入度為0,加入隊尾*/
}
}
}
if(incnt>1) /*如果入度為0的點大於1個,不存在拓撲排序。特別注意此處,不能寫成incnt!=1,因為從最後一個點找,入度為0的點肯定是0,flag會變成0*/
{
flag=0;
break;
}
}
if(j<n||!flag)
printf("No Answer\n");
else
{
for(i=0;i<j;i++)
printf("%c",c[i]);
printf("\n");
}
}
int main()
{
int t,i;
scanf("%d",&t);
while(t--)
{
char A,B;
int a,b;
memset(map,0,sizeof(map));
memset(in,0,sizeof(in));
memset(c,0,sizeof(c));
scanf("%d%d",&n,&m);
getchar();
for(i=1;i<=m;i++)
{
scanf("%c %c",&A,&B);
a=A-'A'+1;
b=B-'A'+1;
map[a][b]=1;
in[b]++;
getchar();
}
toposort();
}
return 0;
}