hdu 1285 确定比赛名次

来源:互联网 发布:传世登陆器源码 编辑:程序博客网 时间:2024/06/03 09:51

注意:这道会重复输入同一个比赛,导致degree变大,要拦阻。


import java.util.Scanner;/* * 思想: * 把数据按要求连起来,就是1->2->3 * -----------------------   4->3 * 这个时候就可以考虑把这道题看成图的遍历 * 于是想到用拓扑排序来输出拓扑序列,这样就瞒足题目了。 * 拓扑排序: * 若在有向图G中存在从顶点vi到vj的一条路径, * 则在顶点序列中顶点vi必须排在顶点vj之前。 * 每次搜索都要把当前结点的邻接的入度减一。 */public class Main {/* * 静态的成员变量相当于全局变量,这是语法问题。 * n,表示n个比赛队 * m,表示m场比赛 * arc-弧,用来保存每一个顶点的出边和入边,数据结构中是叫邻接矩阵。 * visited表示该顶点是否被访问,用0表示未访问,1表示已被访问 * degree表示该顶点的入度数目 */static Scanner sc = new Scanner(System.in);static int n, m;static int arc[][] = new int[501][501];static int visited[] = new int[501];static int degree[] = new int[501];public static void main(String[] args) {while (sc.hasNext()) {n = sc.nextInt();m = sc.nextInt();initialize();topoloySort();}}/* * topoloySort-拓扑排序 */private static void topoloySort() {int s = 0;while (s < n) {/** visited,0表示没有被访问,1表示已被访问* degree,表示当前结点的入度数目* 1)先找到入度为0的结点,入队列* 2)如果i==n,表明该有向图是循环图* 3)输出结果* 4)出队列,找到邻接结点*/int i = 0;for (; i < n; i++) {if (visited[i] == 0 && degree[i] == 0) {visited[i] = 1;break;}}if (i == n) {System.out.println("又向循环图");return;}s++;// 这个要写啊!不然死循环System.out.print(i + 1);if (s < n) {System.out.print(" ");}for (int j = 0; j < n; j++) {if (arc[i][j] == 1) {degree[j]--;}}}System.out.println();}/* * initialize-初始化 */private static void initialize() {// 初始化数据for (int i = 0; i < n; i++) {visited[i] = 0;degree[i] = 0;for (int j = 0; j < n; j++) {arc[i][j] = 0;}}// 输入数据,把剩下的数据初始化for (int i = 0; i < m; i++) {int a = sc.nextInt() - 1;int b = sc.nextInt() - 1;if (arc[a][b] == 0) {// 防止重复比赛arc[a][b] = 1;degree[b]++;}}}}


c++代码

/*一看题目就知道是拓扑排序题,用c++过。这道题m的大小是不确定的,可能会有重复输入,也就是队伍重新比赛。*/#include<iostream>using namespace std;/*这题要用邻接矩阵莱来记录比赛情况。i->j表示i赢j。arc表示临街矩阵degree表示入度visited表示该节点是否被访问*/int n,m;int arc[501][501];int degree[501];int visited[501];void topologySort(int count){    if(count==0){        return;    }    /*    第一步)找到入度为0的结点,    该节点必须是未被访问的,防止重复访问。    然后标记为1,表示该节点已近被访问。    第二步)输出该节点表示的值。    第三步)把该节点的邻居结点的入度减1。    第四步)循环调用指定次数,主要是把所有答案输出。    */    int i=1;    for(;i<=n;i++){        if(degree[i]==0&&visited[i]==0){            visited[i]=1;            break;        }    }    if(i==n+1){        cout<<"又向循环图"<<endl;        return;    }    cout<<i;    if(count>1){        cout<<" ";    }else{        cout<<endl;    }    for(int j=1;j<=n;j++){        if(arc[i][j]==1){            degree[j]--;        }    }    topologySort(--count);}int main(){    while(cin>>n>>m){        /*        初始化数据        */        for(int i=1;i<=n;i++){            degree[i]=0;            visited[i]=0;            for(int j=1;j<=n;j++){                arc[i][j]=0;            }        }        int a,b;        for(int i=1;i<=m;i++){            cin>>a>>b;            if(arc[a][b]==0){                /*                arc[a][b]==0表示同一个比赛,                不能把入度的值加1。                b结点的入度加1                arc[a][b]表示a->b,a赢b。                */                degree[b]++;                arc[a][b]=1;            }        }        topologySort(n);    }    return 0;}




确定比赛名次

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


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 31 22 34 3
 

Sample Output
1 2 4 3
 

Author
SmallBeer(CML)
 

Source
杭电ACM集训队训练赛(VII)  

0 0