hdu 1285 确定比赛名次

本文介绍了一种使用拓扑排序解决比赛排名问题的方法。通过建立邻接矩阵和记录各队伍的胜利关系,实现了对比赛结果的有效处理,最终确定所有参赛队伍的排名顺序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

注意:这道会重复输入同一个比赛,导致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 3 1 2 2 3 4 3
 

Sample Output
  
1 2 4 3
 

Author
SmallBeer(CML)
 

Source

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值