确定比赛名次
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 22158 Accepted Submission(s): 8902
Problem Description
有N个比赛队(1<=N<=500),编号依次为1,2,3,。。。。,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。
Input
输入有若干组,每组中的第一行为二个数N(1<=N<=500),M;其中N表示队伍的个数,M表示接着有M行的输入数据。接下来的M行数据中,每行也有两个整数P1,P2表示即P1队赢了P2队。
Output
给出一个符合要求的排名。输出时队伍号之间有空格,最后一名后面没有空格。
其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。
其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。
Sample Input
4 3 1 2 2 3 4 3
Sample Output
1 2 4 3
下面分别用二维数组,邻接表,队列三种方法,重在理解!
如样例:1入度为0 ,2入度为1 ,3入读为2 ,4入度为0 。依次找到入度为 0 的点输出或存储。
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define CLR(a,b) memset(a,b,sizeof(a))
int n,m;
int mapp[510][510];
int in[510];
int q[510];
void init()
{
CLR(q,0); //数组初始化
for(int i=1;i<510;i++)
{
in[i]=0; //入度全部初始化为 0
for(int j=1;j<510;j++)
mapp[i][j]=0; //所有点之间没有关系为 0
}
}
void top()
{
int t=1;
int next;
int num=0; //记录个数
while(1)
{
for(int j=1;j<=n;j++)
{
if(!in[j]) //取出入度为0的,退出,去判断
{
next=j;
break;
}
}
q[t++]=next; //放进数组
in[next]=-1; //入度变为-1
num++;
for(int i=1;i<=n;i++)
{
if(mapp[next][i]==1)
in[i]--;
}
if(num==n) //n个全部判断,退出
break;
}
for(int i=1;i<t-1;i++)
printf("%d ",q[i]);
printf("%d\n",q[t-1]);
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
init();
int a,b;
for(int i=1;i<=m;i++)
{
scanf("%d %d",&a,&b);
if(mapp[a][b]==0) //防止出现重边,因为如果出现 b 的入度就多了
{
mapp[a][b]=1; //a b确定关系
in[b]++; //b 入度 +1
}
}
top();
}
return 0;
}
邻接表:
邻接表的每一步具体的操作部分虽然是模板但是还是不太理解,先把代码贴上。
关于代码,其他部分和上下两种方法基本一样。 现在好像理解了= . =
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define CLR(a,b) memset(a,b,sizeof(a))
int n,m,num;
int q[510];
int head[510];
int in[510];
struct node
{
int to,next;
}edge[2510];
void init()
{
CLR(head,-1);
CLR(in,0);
num=0;
}
void add(int a,int b)
{
node E={b,head[a]};
edge[num]=E;
head[a]=num++;
in[b]++;
}
void topo(int n)
{
int t,ant=0;
while(1)
{
for(int i=1;i<=n;i++)
{
if(in[i]==0)
{
t=i;
break;
}
}
ant++;
in[t]=-1;
q[ant]=t;
for(int i=head[t];i!=-1;i=edge[i].next)
{
int k=edge[i].to;
in[k]--;
}
if(ant==n)
break;
}
for(int i=1;i<ant;i++)
printf("%d ",q[i]);
printf("%d\n",q[ant]);
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
init();
for(int i=1;i<=m;i++)
{
int a,b;
scanf("%d %d",&a,&b);
add(a,b);
}
topo(n);
}
return 0;
}
队列:
#include<cstdio>
#include<cstring>
#include<queue>
#include<functional> //新的优先队列排序注意这个 头文件
//#include<algorithm>
using namespace std;
#define CLR(a,b) memset(a,b,sizeof(a))
int n,m;
int mapp[510][510];
int in[510];
void init()
{
CLR(mapp,0);
CLR(in,0);
}
void topo()
{
priority_queue<int,vector<int>,greater<int> >q; //队列从小到大排序,新的方法(less从大到小排序)
if(!q.empty())
q.pop();
for(int i=1;i<=n;i++)
{
if(in[i]==0) //找到入度为 0,进队列
q.push(i);
}
int sign=1;
while(!q.empty())
{
int top=q.top();
q.pop();
in[top]=-1; //入度更新
if(sign)
printf("%d",top);
else
printf(" %d",top); //直接输出不需要用一个数组存放
sign=0;
for(int i=1;i<=n;i++)
{
if(mapp[top][i])
{
in[i]--; //更新入度
if(in[i]==0)
q.push(i); //入度为 0进队列
}
}
}
printf("\n");
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
init();
int a,b;
for(int i=1;i<=m;i++)
{
scanf("%d %d",&a,&b);
if(mapp[a][b]==0) //防止出现重边,因为如果出现 b 的入度就多了
{
mapp[a][b]=1; //a b确定关系
in[b]++; //b 入度 +1
}
}
topo();
}
return 0;
}