URAL 1755 Cake

    链接:http://vjudge.net/problem/viewProblem.action?id=24604

    题解:这道题说清楚挺麻烦的,我就盗用一下中山大学 LiYuzhu 同学的题解吧,版权所属,不要来找我。代码一份是他的,一份是我的。


题目大意:
    Karlsson和 LittleBoy想要分割一块含有 n克奶油和 m克巧克力的蛋糕,由 LittleBoy切割,Karlsson先选。每个人对蛋糕的估值函数不同,Little Boy的为 a1x + b1y,Karl的为 a2x + b2y。现给出四个系数和 n,m,求一种能使 LittleBoy收益最大的切割方式。其中,Little Boy可以在不超过 n和 m的范围下,切割出含有任意克奶油和巧克力的蛋糕。而当两块蛋糕对 Karlsson来说估值相同时,Karlsson会让出对 Little Boy 来说估值较高的那一块。


思路:
    首先,想要使 Little Boy的收益最高,约束就是使得两块蛋糕对 Karl来说估值一样。


    设两块蛋糕中任意一块有 x克奶油和 y克巧克力,则应有

              a2x + b2y = a2(n - x) + b2(m - y)


    可以用反证法证明,假设 a2x + b2y < a2(n - x) + b2(m - y),那么 Karl会选择 n–x克奶油和 m–y克巧克力的蛋糕,而 LittleBoy会得到 x克奶油和 y克巧克力的蛋糕。

    但是必定存在 x+Δx和 y+Δy,使得

             a2(x + Δx) + b2(y + Δy) = a2(n – x -Δx) + b2(m – y - Δy)成立,

    而这时对 LittleBoy来说,显然 x+Δx克奶油和 y+Δy克巧克力的蛋糕相比原来的蛋糕收益更高。

             a2x + b2y > a2 (n - x) + b 2(m - y) 的情况同理可证。


    答案只要求输出符合题意的任意一种分割方法中的任意一块的含奶油和巧克力量,不妨设 LittleBoy得到的是(x,y)的那一块。

    题目要求让 LittleBoy的估值函数 V = a1 x + b1 y 最大。从 a2x + b2y = a2(n - x) + b2(m - y)可以得到 y和 x的关系式,代入函数 V中,可得到 V和 x的关系式,为一次函数 V(x) = kx + b。

    接下来只要根据 k的正负,来确定使得 V(x)最大的 x的值,在通过上面的约束条件算出 y即可,注意需确保 x和 y在取值范围内。

    如果 k < 0,则确保 x越小越好,因此直接取 x = 0,算出 y,判断 y是否在 0 ~ m 范围内,如果不在,则令 y = m,反算出 x 即可。

    如果 k > 0,则确保 x越大越好,因此直接取 x = n,算出 y,判断 y是否在 0 ~ m 范围内,如果不在,则令 y = 0,反算出 x 即可。

    如果 k = 0 的,代表可以随意确定 x,那么随便套用上面一种情况即可。


    有几种特殊情况:

    通过计算可知 k = a 1 – a2 * b1 / b 2,而且在确保 x和 y在取值范围内时 a 2 也会出现在分母,因此对于 a 2 和 b 2 等于 0的情况特殊对待。

     a2 =b2 =0,则 x = n,y = m,即 LittleBoy拿走全部

     a2 = 0, b2 ! = 0 ,则 x = n,y = m / 2,即 LittleBoy拿走全部奶油,而巧克力对半分即可

     a2 ! =0 ,b 2 =0 , 则 x = n / 2,y = m,即 LittleBoy拿走全部巧克力,而奶油对半分即可


LiYuzhu 同学的代码:

#include<iostream>
#include<iomanip>

using std::cin;
using std::cout;
using std::endl;

int main(void)
{
    double a1,b1,a2,b2;
    double n,m;
    double x,y;
    cin>>a1>>b1>>a2>>b2;
    cin>>n>>m;
    //步骤 1
    if(a2==0 && b2==0)
    {
        x=n;
        y=m;
    }
    else if(a2==0&&b2!=0)
    {
        x=n;
        y=m/2;
    }
    else if(a2!=0&&b2==0)
    {
        x=n/2;
        y=m;
    }
    //步骤 2,y和 x的关系式均由约束方程化简得到
    else if((a1-a2 *b1/b2)<0.0)
    {
        x=0;
        y=(n*a2/b2+m)/2;
        if(y>m)
        {
            y=m;
            x=(n-m*b2/a2)/2;
        }
    }
    else if((a1-a2 *b1/b2)>0.0)
    {
        x=n;
        y=((n-2*x)*a2/b2+m)/2;
        if(y<0)
        {
        y=0;
        x=(n+m*b2/a2)/2;
        }
    }
    else
    {
        x=0;
        y=(n*a2/b2+m)/2;
        if(y>m)
        {
            y=m;
            x=(n-m*b2/a2)/2;
        }
    }

    //步骤 3
    cout<<std::setiosflags(std::ios::fixed)<< std::setprecision(8)<<x<<" "<<y<<endl;

    return 0;
}

我的:

#include <iostream>
#include <cstring>
#include <string>
#include <iomanip>

using namespace std;

int main()
{
	double a1,b1,a2,b2;
	double x,y;

	cin>>a1>>b1>>a2>>b2;
	cin>>x>>y;

	double h = (a2*x + b2*y)/2.0;

	double y1 = h/(b2*1.0);
	double x2 = (h - b2*y)/(a2*1.0);
	double x3 = h/(a2*1.0);
	double y4 = (h - a2*x)/(b2*1.0);

	double ness = 0;
	double ansx,ansy;

	if(y1 >= 0 && y1 <= y)
	{
		if(b1*y1 > ness)
		{
			ansx = 0,ansy = y1;
		}
	}
	else if(x2 >= 0 && x2 <= x)
	{
		if(a1*x2 + b1*y > ness)
		{
			ansx = x2,ansy = y;
		}
	}
	else if(x3 >= 0 && x3 <= x)
	{
		if(a1*x3 > ness)
		{
			ansx = x3,ansy = 0;
		}
	}
	else if(y4 >= 0 && y4 <= y)
	{
		if(a1*x + b1*y4 > ness)
		{
			ansx = x,ansy = y4;
		}
	}

	cout<<fixed<<setprecision(8)<<ansx<<' '<<fixed<<setprecision(8)<<ansy<<endl;

	return 0;
}
	

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值