您的位置:首页 > 其它

JZOJ 5407. 【NOIP2017提高A组集训10.21】Deep

2017-10-22 06:48 411 查看

题目大意

双方分别有A,B张牌,A先手。

A和B每次可以选择2个操作:

①出牌,让传送门的值+1。

②不出牌,让对方得分加上传送门的值,然后传送门的值变为0。

注意,当自己的牌数>0且传送门的值为0时不能进行②操作。

题解

打个表发现,其实结论很显然。如果A>0,B>0,答案为A-B-2,否则为A-B。

此结论可以证明。

其实策略不止一种。

策略1:后手总是存在这样的策略:将对方的牌打剩最后一张,然后开始出牌。

因为一旦后手选择出牌,则先后手互换,先手有类似的策略。

策略2:B可以将A的牌数消耗至B-1张,然后双方你一张我一张然后你不出。那么这个阶段A和B得分可以抵消。最后B还剩一张牌,B+1分,得到上述结论。

总结

①这道题最重要的是知道显然有结论。

②问题是怎么打表。

按照博弈规则,A希望分差A-B越大,B希望A-B越小。

那么记录一下当前先手是谁,到A走的时候,就返回得分的max,B就返回得分的min。

博弈的代码(非AC代码)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int ans,a,b,T;
int dg(int a,int b,int door,int v,int bz){
if(!a&&!b&&!door)return v;
if(bz){//A出牌,max环节
int mx=-2147483647;
if(door!=0||!a)mx=max(mx,dg(a,b,0,v-door,0));
if(a>0)mx=max(mx,dg(a-1,b,door+1,v,0));
return mx;
}else{//B出牌,min环节
int mi=2147483647;
if(door!=0||!b)mi=min(mi,dg(a,b,0,v+door,1));
if(b>0)mi=min(mi,dg(a,b-1,door+1,v,1));
return mi;
}
}
int main(){
freopen("deep.in","r",stdin);
freopen("deep.out","w",stdout);
scanf("%d",&T);
while(T--){
scanf("%d%d",&a,&b);
ans=dg(a,b,0,0,1);
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: