zoukankan      html  css  js  c++  java
  • HDU 1285 确定比赛名次

    传送门

    确定比赛名次

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


    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
     
    Recommend
    lcy
    -------------------------------------------------------------------------------------------------------------------------
    我的错误解法
     
    #include <bits/stdc++.h>
    using namespace std;
    const int N(500+5);
    vector<int> g[N];
    bool vis[N];
    int topo[N], tot;
    void dfs(int u){
        vis[u]=1;
        for(int i=0; i<g[u].size(); i++){
            int &v=g[u][i];
            if(vis[v]) continue;
            dfs(v);
        }
        topo[--tot]=u;
    }
    int main(){
        for(int n, m; ~scanf("%d%d", &n, &m);){
            for(int i=1; i<=n; i++) g[i].clear();
            for(int u, v; m--;) scanf("%d%d", &u, &v), g[u].push_back(v);
            for(int i=1; i<=n; i++) sort(g[i].begin(), g[i].end(), greater<int>());
            memset(vis, 0, sizeof(vis)); tot=n;
            for(int i=n; i; i--) if(!vis[i]) dfs(i);
            printf("%d", topo[0]); for(int i=1; i<n; i++) printf(" %d", topo[i]); puts(""); 
        }
    }
    首先总的想法是DFS拓扑排序,由于题目要求输出字典序最小的排列,对DFS的顺序做一些修改:
    (1)将每个节点的邻接表从大到小排序
    (2)在主函数内,按照节点编号从大到小的顺序调用DFS
    这两个修改虽然方向是对的,但还是有问题的。
    比如,样例
    5 4
    5 2
    2 4
    5 3 
    3 1
    正确输出是
    5 2 3 1 4
    但我的代码输出:
    5 2 4 3 1
    这个题目的输出要解决的问题是:
    保证先后关系不确定的节点中,序号小的在前。
    (注意,上面用的词是先后关系,而非胜负关系。因为,假如知道了 A胜B, B胜C 那么A, B, C三者的先后一定是 A B C 但A和C的胜负关系是不知道的。)
    能否在不改变DFS框架的前提下,使输出正确呢?
     ---------------------------------------------------------------------------------------
    正解是:迭代
    每次选择入度为0且编号最小的点u输出,将u删除,并将u的临接表中的点的入度减一。
    (这种解法不需要处理重边
     
    #include <bits/stdc++.h>
    using namespace std;
    const int N(500+5);
    vector<int> g[N];
    int in[N];
    int main(){
        for(int n, m; ~scanf("%d%d", &n, &m);){
            for(int i=1; i<=n; i++) g[i].clear();
            memset(in, 0, sizeof(in));
            for(int u, v; m--;) scanf("%d%d", &u, &v), g[u].push_back(v), in[v]++;
            for(int i=0; i<n; )
                for(int u=1; u<=n; u++){
                    if(in[u]==0){
                        if(!i++) printf("%d", u);
                        else printf(" %d", u);
                        in[u]=-1;
                        for(int j=0; j<g[u].size(); j++){
                            int &v=g[u][j]; in[v]--;
                        }
                        break;
                    }
                }
            puts("");
        }
    }
    还可用堆优化
    #include <bits/stdc++.h>
    using namespace std;
    const int N(500+5);
    vector<int> g[N];
    int in[N];
    typedef pair<int,int> P;
    priority_queue<P, vector<P>, greater<P> > que;
    int main(){
        for(int n, m; ~scanf("%d%d", &n, &m);){
            for(int i=1; i<=n; i++) g[i].clear();
            memset(in, 0, sizeof(in));
            for(int u, v; m--;) scanf("%d%d", &u, &v), g[u].push_back(v), in[v]++;
            for(int i=1; i<=n; i++) que.push({in[i], i});
            bool first=true;
            while(!que.empty()){
                P top=que.top(); que.pop(); int &u=top.second;
                if(in[u]!=top.first) continue;
                if(first) printf("%d", u), first=false;
                else printf(" %d", u);
                for(int i=0; i<g[u].size(); i++){
                    int &v=g[u][i];
                    que.push({--in[v], v});
                }
            }
            puts("");
        }
    }
     
     
  • 相关阅读:
    解决iOS app集成共享QQ场地,微信的朋友,朋友等功能圈,不能采用苹果公司的审计问题
    沙朗新闻发布系统汇总
    Cocos2d-x示例:单点触摸事件
    【UVA272】TEX Quotes
    Android多线程的研究(8)——Java5于Futrue获取线程返回结果
    Spring Assert主张 (参议院检测工具的方法-主张)
    redmine使用汇总redmine软件工程过程
    IIS7构造Gzip压缩
    PHPthinking官方论坛
    javaweb学习总结(十一)——使用Cookie进行会话管理
  • 原文地址:https://www.cnblogs.com/Patt/p/4816479.html
Copyright © 2011-2022 走看看