CodeForces 94D End of Exams (贪心)

题目链接:http://codeforces.com/problemset/problem/94/D

D. End of Exams
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
Students love to celebrate their holidays. Especially if the holiday is the day of the end of exams!

Despite the fact that Igor K., unlike his groupmates, failed to pass a programming test, he decided to invite them to go to a cafe so that each of them could drink a bottle of… fresh cow milk. Having entered the cafe, the m friends found n different kinds of milk on the menu, that’s why they ordered n bottles — one bottle of each kind. We know that the volume of milk in each bottle equals w.

When the bottles were brought in, they decided to pour all the milk evenly among the m cups, so that each got a cup. As a punishment for not passing the test Igor was appointed the person to pour the milk. He protested that he was afraid to mix something up and suggested to distribute the drink so that the milk from each bottle was in no more than two different cups. His friends agreed but they suddenly faced the following problem — and what is actually the way to do it?

Help them and write the program that will help to distribute the milk among the cups and drink it as quickly as possible!

Note that due to Igor K.’s perfectly accurate eye and unswerving hands, he can pour any fractional amount of milk from any bottle to any cup.

Input
The only input data file contains three integers n, w and m (1 ≤ n ≤ 50, 100 ≤ w ≤ 1000, 2 ≤ m ≤ 50), where n stands for the number of ordered bottles, w stands for the volume of each of them and m stands for the number of friends in the company.

Output
Print on the first line “YES” if it is possible to pour the milk so that the milk from each bottle was in no more than two different cups. If there’s no solution, print “NO”.

If there is a solution, then print m more lines, where the i-th of them describes the content of the i-th student’s cup. The line should consist of one or more pairs that would look like “b v”. Each such pair means that v (v > 0) units of milk were poured into the i-th cup from bottle b (1 ≤ b ≤ n). All numbers b on each line should be different.

If there are several variants to solve the problem, print any of them. Print the real numbers with no less than 6 digits after the decimal point.


题目大意: 给定一个数字n,代表一共有n瓶不同的牛奶。给定数字w,代表每瓶牛奶的量。给定数字m,代表着要均分到m个杯子当中。条件为每一种牛奶只能出现在两个杯子当中。给出是否可行,如果可行则给出每个杯子当中是如何配比的。

解析:先不去管限定条件,直接把牛奶平分进m个杯子中,记录下方法。每个杯子当中应该有奶量 n*w/m。如果当前杯子没满,那就倒满,然后继续处理下一个杯子; 如果倒入杯子的过程中,瓶子中的奶没倒完,那就尽可能倒进杯子里,如果不够,启用下一个瓶;如果杯子满了,那就求解下一个杯子。如此,确定了配比方法之后,遍历确认是否每瓶牛奶都只用了两次。

坑点和吐槽:注意double的精度问题,做判断的时候如果使用0作为瓶子中是否还有牛奶,和杯子中的奶量是否满,则会死循环。(被卡的我,眼泪流下来)


AC代码如下:

#include <iostream>
#pragma comment(linker, "/STACK:1024000000,1024000000") 
#include <stdio.h>
#include <fstream>
#include <iomanip>
#include <cmath>
#include <string>
#include <string.h>
#include <sstream>
#include <cctype>
#include <climits>
#include <set>
#include <map>
#include <deque>
#include <queue>
#include <vector>
#include <iterator>
#include <algorithm>
#include <stack>
#include <functional>
//cout << "OK" << endl;
#define _clr(x,y) memset(x,y,sizeof(x))
#define _inf(x) memset(x,0x3f,sizeof(x))
#define pb push_back
#define mp make_pair
#define FORD(i,a,b) for (int i=(a); i<=(b); i++)
#define FORP(i,a,b) for (int i=(a); i>=(b); i--)
#define REP(i,n) for (int i=0; i<(n); i++)
using namespace std;
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
const double EULER = 0.577215664901532860;
const double PI = 3.1415926535897932384626;
const double E = 2.71828182845904523536028;
typedef long long LL;
LL pow_mod(LL a,LL n,LL m)
{
    if(n == 0) return 1;
    LL x = pow_mod(a,n>>1,m);
    LL ans = x*x%m;
    if(n&1) ans = ans*a%m;
    return ans;
}
int gcd(int a,int b){return b == 0 ? a : gcd(b,a%b);}


typedef struct{
    double remain;
    int cont;
}data;
//瓶子的数据 
typedef struct{
    int index[60];
    double num[60];
    int cont;
}ans;
//杯子的数据 
int main(){
    data arr[60];
    ans cup[60];
    int n,w,m;
    cin >> n >> w >> m;
    FORD(i,1,n){
        arr[i].remain = w;
        arr[i].cont = 0;
    }
    FORD(i,1,m){
        cup[i].cont = 0;
    }
    double volume = 1.0*n*w/m;
    bool valid = true;
    //初始化过程,将杯子瓶子的计数都设为0,瓶子的计数代表用了几次,杯子的计数代表杯子中有几种奶 
    FORD(i,1,m){
        //对第i个杯子求解 
        double temp = volume;
        while(temp > eps){//这里判断条件要用大于eps(精度为1e-8) 
            for(int j = 1; j <= n; j++){
                if(arr[j].remain > eps){
                    //如果瓶子里的奶没有倒完,判断是杯子需要的多,还是瓶子中剩下的多 
                    double tmp = min(arr[j].remain, temp);
                    arr[j].remain -= tmp;
                    arr[j].cont++;
                    temp -= tmp;
                    //记录下当前倒入杯子的奶的种类,和倒入的量 
                    cup[i].index[cup[i].cont] = j;
                    cup[i].num[cup[i].cont] = tmp;
                    cup[i].cont++;
                    //如果这次倒完之后,杯子满了,直接求解下一个杯子 
                    if(temp <= eps){
                        break;
                    }
                }
            }
        }
    }
    //判断是否每个瓶子只用了两次 
    FORD(i,1,n){
        if(arr[i].cont > 2){
            valid = false;
            break;
        }
    }
    if(!valid){
        cout << "NO" << endl; 
    }
    else{
        cout << "YES" << endl;
        FORD(i,1,m){
            FORD(j,0,cup[i].cont-1){
                if(j) cout << " ";
                cout << cup[i].index[j] << " " << fixed << setprecision(6) << cup[i].num[j];
            }
            cout << endl;
        }
    }
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值