zoukankan      html  css  js  c++  java
  • UVa 1612 Guess (贪心+题意)

    题意:有 n 位选手参加编程比赛。比赛有3道题目,每个选手的每道题目都有一个评测之前的预得分(这个分数和选手提交程序的时间相关,提交的越早,预得分越大)。

    接下来 是系统评测。如果某道题未通过测试,则改题的实际得分为0分,否则得分等于预得分。得分相同的选手,ID小的排在前面。

    问是否能给出所有3n个得分以及最后的实际名次。如果可能,输出最后一名的最高可能得分。每个预得分均为小于1000的非负实数,最多保留两位小数。

    析:首先这个题是一个水题,一点也不难,我就卡在题意上了,卡了一下午,吃饭回来又读了几遍题意才明白,就是给定的ID,这个按名次排的,

    也就是说 第 i 个数是名次为 i 的ID,这个地方一定要搞清楚,剩下的就好说了,先按名次从小到大排序,然后从 1 到 n 进行比较,如果当前的总分比前一个要小,

    或者总分一样而当前的ID的大,那么就这样,不用改变,如果都不成立,那么就找离他们差值最小的组合,然后用总和减去就行,这个地方在选的时候利用暴力,

    一共才3个题,所以可以用二进制法进行枚举,然后找出最接近那一个,如果都所有的都不行,那么就是无解,直接结束就好了。

    这个题要注意精度问题,这个很重要的,由于题意说了,最多两位小数,那么可以扩大100倍,最后再除以100,就不用考虑精度了。

    代码如下:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #include <set>
    #include <cstring>
    #include <cmath>
    
    using namespace std;
    const int maxn = 16384 + 5;
    const int INF = 0x3f3f3f3f;
    struct node{
        int score[3];//分数
        int id, ran;
        int getsum(){  return score[0] + score[1] + score[2];  }//返回总分,其实也可以定义一个和变量的
        bool operator < (const node &p) const{//按照名次排序
            return ran < p.ran;
        }
        
    };
    node a[maxn];
    
    bool solve(int n, int val, bool ok){//第一个参数是要改的哪一个下标,第二个是差值,找和它最近的,
        //第三个是判断两个ID是不是当前的大于前一个,用来判断是否可以相等
        int num[10];//记录所有的分数可能性
        vector<int> v[10];//记录下标,也可不用
        for(int i = 0; i < 8; ++i){//二进制枚举
            num[i] = 0;
            for(int j = 0; j < 3; ++j)
                if(i & (1<<j)){  num[i] += a[n].score[j]; v[i].push_back(j);  }
        }
    
        int m = INF;
        int t = -1;
        for(int i = 0; i < 8; ++i)  if((ok && num[i] >= val) || (num[i] > val))//判断是不是大于或者大于等于,
            if(num[i] < m){  m = num[i];  t = i; }
        if(-1 == t)  return false;//如果都找不到,也可以在开始时特,那样会节约时间
        for(int i = 0; i < v[t].size(); ++i)//把删除的清0
            a[n].score[v[t][i]] = 0;
        return true;
    }
    
    int main(){
    //    freopen("in.txt", "r", stdin);
        int n, kase = 0;
        while(scanf("%d", &n) == 1 && n){
            for(int i = 0; i < n; ++i)
                for(int j = 0; j < 3; ++j){
                    double x;  scanf("%lf", &x);
                    a[i].score[j] = (int)round(x * 100.0);//主要是把实数变成整数,用的是round函数,四舍五入
                }
            int x;
            for(int i = 0; i < n; ++i){  scanf("%d", &x);  a[x-1].ran = i; a[x-1].id = x;   }//一定要注意,输入到底是什么
            sort(a, a+n);
    
            bool ok = true;
            for(int i = 1; i < n; ++i){
                int s = a[i].getsum(), t = a[i-1].getsum();
                if(s < t || (s == t && a[i].id > a[i-1].id))  continue;//当前的小于前一个或者相等但ID当前的大
    
                if(!solve(i, s - t, a[i].id > a[i-1].id)){ ok = false;  break; }//如果找不到,直接结束
            }
    
            printf("Case %d: ", ++kase);
            ok ? printf("%.2lf
    ", (double)a[n-1].getsum()/100.0) : printf("No solution
    ");//最后再除100,变回去
        }
        return 0;
    }
    
  • 相关阅读:
    菜鸟fork()创建进程新见解
    Linux下select函数的使用
    URAL 1029 Ministry
    URAL 1036 Lucky Tickets
    URAL 1031 Railway Tickets
    URAL 1028 Stars
    URAL 1032 Find a Multiple
    URAL 1037 Memory Management
    URAL 1033 Labyrinth
    URAL 1039 Anniversary Party
  • 原文地址:https://www.cnblogs.com/dwtfukgv/p/5618383.html
Copyright © 2011-2022 走看看