图 相关题目 Ⅲ

[hdu 1285] (http://acm.hdu.edu.cn/showproblem.php?pid=1285)
题目描述:
确定比赛名次

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 17588 Accepted Submission(s): 7026

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. 此题建图运用链式前向星的方法;
2. 利用拓扑排序时,加入优先队列,可以实现自动从小到大的排序,即可以实现题目中所要求的序号小的排在前面,具体代码实现如下:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
#include <vector>
#include <functional>
using namespace std;

const int N=505;
int head[N*N];
int ip;
int n,m,p1,p2,seq[N*N];
int indegree[N];//用于存储点的入度
struct edgenode
{
    int to;
    int next;
} edge[N*N];

void add(int u,int v)
{
    edge[ip].to=v;
    edge[ip].next=head[u];
    head[u]=ip++;
}
int tope()
{
    priority_queue<int,vector<int>,greater<int> >q;//利用优先队列从小到大进行排序
    int indeg[N];
    for(int i=1; i<=n; i++)
    {
        indeg[i]=indegree[i];
        if(indeg[i]==0)//将入度为0的下标插入队列队尾
            q.push(i);
    }
    int k=0;
    bool res=false;
    while(!q.empty())//当队列不为空时
    {
        if(q.size()!=1) res=true;
        int u=q.top();//把队首元素赋给u //1. int u=q.top();在优先队列中使用 //2. int u=q.front();在普通队列中使用
        q.pop();//删除队首元素
        seq[k++]=u;
        for(int i=head[u]; i!=-1; i=edge[i].next)
        {
            int v=edge[i].to;
            indeg[v]--;
            if(indeg[v]==0)//将入度为0的下标插入队列队尾
                q.push(v);
        }
    }
    //if(k<n) return -1;//存在有向环,不能进行拓扑排序
    if(res) return 0;//排序有唯一种解,seq数组即为排好的
    return 1;//排序有多种解,由于经过STL队列处理,seq为序号最小的一种
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(head,-1,sizeof(head));
        ip=0;
        memset(indegree,0,sizeof(indegree));
        memset(seq,0,sizeof(seq));
        for(int i=0; i<m; i++)
        {
            scanf("%d%d",&p1,&p2);
            add(p1,p2);
            indegree[p2]++;//记录入度
        }
        int t=tope();
        if(t==0||t==1)
            for(int i=0; i<n; i++)
            {
                printf(i==n-1?"%d\n":"%d ",seq[i]);
            }
    }
    return 0;
}

你可能感兴趣的:(图,拓扑排序,链式前向星)