练习 4

描述

Alice和Bob都要向同一个商人购买钻石。商人手中有 N 颗钻石,他会将它们一颗颗地卖给他们,Alice和Bob通过竞价的方式来决定钻石的归属。具体的过程如下:商人首先指定其中一个人开始报价,之后两人轮流报价,要求是一定要比对方报的价格更高。任何时候,如果一个人不愿出价或者出不起价钱时,可以宣布弃权,则对手以最后一次报的价格将钻石买下。当然,如果两人都没钱,商人是不会卖钻石的。首次报价至少为 1,并且只能报整数的价钱。

Alice和Bob特别爱攀比,因此他们都希望能比对方买到更多的钻石。Alice和Bob各自带了 CA 和 CB 的钱用于竞拍钻石。此外,Alice和商人有很不错的私人关系,因此商人总是会让Alice先报价。现在请问,在Alice和Bob都用最优策略的情况下,谁能买到更多钻石?假设双方都知道对方手中的现金数量,以及商人将要拍卖的钻石数量 N。

输入

输入文件包含多组测试数据。

第一行,给出一个整数T,为数据组数。接下来依次给出每组测试数据。

每组数据为三个用空格隔开的整数 N,CA,CB,表示钻石的数量,以及双方带的现金数量。

输出

对于每组测试数据,输出一行"Case #X: Y",其中X表示测试数据编号,Y的取值为{-1, 0, 1},-1表示Alice买到的钻石会比Bob少,0表示两人能买到一样多,1表示Alice能买到更多钻石。所有数据按读入顺序从1开始编号。

数据范围

1 ≤ T ≤ 1000

小数据:0 ≤ N ≤ 10; 0 < CA, CB ≤ 10

大数据:0 ≤ N ≤ 105; 0 < CA, CB ≤ 106



这次没有去分析,而是想着怎么计算出来。然后算出来了。结果跟我说,别人都是分析的。。。唉,感觉我的解法也应该是正确的吧。


计算的方法是,先由a对所有钻石进行第一次竞价。而b肯定只能在a上进行竞价,就算之后有空余的,a没有足够的钱去竞价,但是,b去竞价最后的与a留钱竞价最后的钻石,以及a直接竞价之前的钻石的情况是相同的。而如果b想要获得更多的钻石就必须去与a已竞价的钻石去竞价

然后b每竞价一次,获得了一颗钻石,而a为此刻钻石的预算也将回到a的手中,用于竞价下一颗钻石,而不是这一颗,因为这样效率明显不高。a将多于的钱用于竞价之前未竞价的空白钻石,这里可以发现,为什么b不在这个阶段对其他钻石进行第一次竞价了,因为没有意义,所有钻石的第一次竞价肯定是a的。或者a加钱加在自己之前竞价的钻石上,以防止被b竞价。

然后b循环竞价,知道b剩余的钱不够用了,或者a的钱不够用了。然后结果就出来了。

这样做甚至能获得双方都进行最佳策略时的购买过程,但是 ,没有意义。。。


#include "stdafx.h"
#include <iostream>
using namespace std;
int NA,NB,CA,CB,N;//ab的余额和已购买到的钻石数
int nowA,nowB;//现在ab的剩余金额
int sprice[2][2];//下一次开始加价时,ab所需的价格,以及位置。
int dia[105][2];//1为a,0为无 -1为b,第二个数据为现在的price
void Abuy(){
	while( sprice[0][1] < N){
		if(nowA == 0)break;
		if( NA ==0 && CA < sprice[0][0])break;
		if( dia[sprice[0][1] ][1] == sprice[0][0]){
			if(sprice[0][1] == N-1){//如果填满一行,到b所在行去填充
				sprice[0][0] = sprice [1][0];
				sprice[0][1] = sprice [1][1];
			}else
				sprice[0][1]++;
			continue;//当此已经被对方叫价时,跳过 
		}
		if( dia[sprice[0][1] ][0] == 1){
			nowA --;
			//NA ++;
			dia[sprice[0][1] ][1]++;
		}else if(dia[sprice[0][1] ][0] == 0){
			nowA --;
			NA ++;
			dia[sprice[0][1] ][1]++;
		}
		else
		{
			if(nowA < sprice[0][0]){
				if(sprice[0][1] == N-1){//如果填满一行,到b所在行去填充
				sprice[0][0] = sprice [1][0];
				sprice[0][1] = sprice [1][1];
			}else
				sprice[0][1]++;
				continue;
			}
			nowA -= sprice[0][0];//不同情况消耗不同
			NA ++;
			NB --;
			nowB += sprice[0][0] -1;
			dia[sprice[0][1] ][1]++;
		}
		dia[sprice[0][1]][1] = sprice[0][0]; 
		dia[sprice[0][1]][0] = 1;	

		if(sprice[0][1] == N-1){//如果填满一行,到b所在行去填充
		sprice[0][0] = sprice [1][0];
		sprice[0][1] = sprice [1][1];
	}else
		sprice[0][1]++;
	}
	
}
void Bbuy(){//低层的肯定被a填满,除非。。。a=0。。。
		if(nowB == 0)return;
		if( NB ==0 && CB < sprice[1][0])return;
		if( dia[sprice[1][1] ][1] == sprice[1][0]){
			if(sprice[1][1] == N-1){//如果填满一行,到b所在行去填充
			sprice[1][0] ++;
			sprice[1][1] = 0;
			}else
				sprice[1][0] ++;
			return;//当此已经被对方叫价时,跳过 
		}
		if( dia[sprice[1][1] ][0] == -1){
			nowB --;
			//NB ++;
			dia[sprice[1][1] ][1]++;
		}else if(dia[sprice[1][1] ][0] == 0){
			nowB --;
			NB ++;
			dia[sprice[1][1] ][1]++;
		}
		else
		{
			if(nowB < sprice[1][0]){
				if(sprice[1][1] == N-1){//如果填满一行,到b所在行去填充
			sprice[1][0] ++;
			sprice[1][1] = 0;
			}else
				sprice[1][0] ++;
				return;
			}
			nowB -= sprice[1][0];//不同情况消耗不同
			NB ++;
			NA --;
			dia[sprice[1][1] ][1]++;
			nowA += sprice[1][0] -1;
		}
		dia[sprice[1][1]][1] = sprice[1][0]; 
		dia[sprice[1][1]][0] = -1;	

		if(sprice[1][1] == N-1){//如果填满一行,到b所在行去填充
		sprice[1][0] ++;
		sprice[1][1] = 0;
	}else
		sprice[1][1]++;
	Abuy();
}
int startbuy(){

if(CA < N/2){
		if(CB > CA )
			return -1;
		if(CB == CA)
			return 0;
		else return 1;
	}
	sprice [0][0] = 1;//将要加价的价格
	sprice [0][1] = 0;//将要加价的钻石编号,从0 到 N-1;
	sprice [1][0] = 2;
	sprice [1][1] = 0;
	for( int i=0;i< N;i++){
		dia[i][0] = 0;
		dia[i][1] = 0;
	}
	NA = 0;
	NB = 0;
	nowA = CA;
	nowB = CB;
	Abuy();
	while(1){
	if( CB < sprice[1][0])break;
	if( nowB == 0 )break;
	Bbuy();
	}
	if(NA == NB)return 0;
	if( NA < NB)return -1;
	return 1;
}
int main()
{
	int T;
	//int N;
	//int N,CA,CB;

	int K=1;
	cin>>T;
	while(T--){
		cin>>N>>CA>>CB;
		printf ("Case #%d:",K++);
		cout<<startbuy()<<endl;
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值