首页 > 其他分享 >题解:UVA1500 Alice and Bob

题解:UVA1500 Alice and Bob

时间:2024-10-02 17:47:19浏览次数:6  
标签:return 包含 min int 题解 石子 Alice dfs Bob

  1. 状态表示
  • 使用两个变量来表示当前游戏的状态:\(a\) 表示包含 \(1\) 个石子的堆的数量,\(b\) 表示包含多于 \(1\) 个石子的堆的可操作次数。
  1. 游戏策略
    1. 从包含多个石子的堆中取走一个石子,这会减少 \(b\)。
    1. 从包含 \(1\) 个石子的堆中取走一个石子,这会减少 \(a\)。
    1. 合并两个包含 \(1\) 个石子的堆,变成一个包含多个石子的堆。这会减少 \(a\) 并增加 \(b\)。
    1. 将一个包含 \(1\) 个石子的堆合并到包含多个石子的堆中,这会减少 \(a\) 并增加 \(b\)。
  1. 临界情况
  • 如果当前所有堆中石子数量都为 \(1\)(\(a > 0\) 且 \(b = 0\)),那么最终会剩下一个石子,这时轮到操作的玩家输。
  • 如果所有堆都包含多个石子,且可操作次数 \(b\) 为奇数,那么先手玩家有必胜策略。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6;
int n,f[50][N];
//f[i][j]表示有i个1,大于1的堆有j此操作。
int dfs(int a,int b) {
	if(f[a][b]!=-1)return f[a][b];//记忆化
	if(!a)return f[a][b]=b%2;
	//若全是大于1的堆,b为奇数则先手必赢
	if(b==1)return dfs(a+1,0);//没有大于1的堆
	int t=2;
	if(b)t=min(t,dfs(a,b-1));//取走大于1的堆中一个元素
	if(a)t=min(t,dfs(a-1,b));//取走1的堆中一个元素
	if(a>1)t=min(t,dfs(a-2,b+2+(b?1:0)));//将两个1合并
	if(a&&b)t=min(t,dfs(a-1,b+1));//1合并到大于2的堆中
	if(!t)f[a][b]=1;
	else f[a][b]=0;
	return f[a][b];
}
int main() {
	int T;
	cin>>T;
	memset(f,-1,sizeof(f));
	for(int k=1; k<=T; k++) {
		int a=0,tot=0;
		cin>>n;
		for(int i=1; i<=n; i++) {
			int x;
			cin>>x;
			if(x==1)a++;
			else tot+=x+1;
		}
		if(tot)tot--;
		//可操作数==堆数+求和(堆中元素数)-1
		cout<<"Case #"<<k<<": ";
		if(dfs(a,tot))
			cout<<"Alice"<<endl;
		else cout<<"Bob"<<endl;
	}
}

标签:return,包含,min,int,题解,石子,Alice,dfs,Bob
From: https://www.cnblogs.com/cly312/p/18444917

相关文章

  • 题解:P9788 [ROIR 2020 Day2] 区域规划
    法1枚举\(a,b,c\),考虑到\(c\)的最小值为\(\max(1,\frac{(a\cdotb−n)}{b})\),所以直接剪枝即可通过。代码:#include<bits/stdc++.h>usingnamespacestd;intans,n,m;intmain(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>n>>m; for(i......
  • 题解:UVA124 Following Orders
    考虑深搜和拓扑排序。从入度为零的节点开始,逐步添加到当前的排列结果中,并在每一步递减相邻节点的入度。如果某个节点的入度变为零,就递归地将其添加到当前排列中。一旦达到排列的叶节点,就存储起来,并按字典顺序排序。代码:#include<bits/stdc++.h>usingnamespacestd;voidread......
  • 题解:UVA117 The Postal Worker Rings Once
    此题要求我们求欧拉回路的长度。使用Floyd算法计算图中任意两点之间的最短路径,对于度数为奇数的路口(最多有两个),找到它们之间的最短路径并将其加入总路径长度中。代码:#include<bits/stdc++.h>#defineINF1e8usingnamespacestd;intdegree[26];intpath[26][26];intal......
  • 题解:SP15553 STC00 - Hamsters
    首先,通过预处理计算每个名字的哈希值,然后利用哈希检查名字之间的最长公共前缀,从而确定从一个名字转移到另一个名字的最小代价。使用倍增动态规划计算转移的最小成本,\(f_{t,i,j}\)表示从名字\(i\)经过\(2^t\)步转移到名字\(j\)的最小代价,最后通过位运算处理\(M\)次转移的......
  • 题解:AT_abc373_d [ABC373D] Hidden Weights
    可以发现一个性质:对于图的每个连通分量,一旦在其中任何顶点上的值固定,则所有写入的值都是确定的。我们可以逐个DFS每个连通分量,按照题目的要求给每个点赋值,初始搜索的点值设成\(0\)即可。代码:#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;intn,m;......
  • 题解:SP19382 STK - Stock
    一道动态规划题。先分析状态。\(dp_{i\operatorname{and}1,k}\):表示在第\(i\)天最多进行\(k\)次交易的最大利润。\(s_{i\operatorname{and}1,k}\):表示在第\(i\)天之前的某天卖出之后,最多进行\(k-1\)次交易的最大利润减去当天的价格。接下来分析转移方程当\(i=0\)......
  • 题解:SP23875 DCEPC14A - Another Version of Inversion
    我们注意到这道题是二维的,所以要用到二维树状数组,不会的可以看一下这篇文章。这题的思路和P1908很像,按价值从大到小排序,排完序之后用树状数组维护,每次把这个数的位置加入到树状数组中,因为是排完序之后,所以之前加入的一定比后加入的大,然后在查询当前这个数前面位置的数(是前面位......
  • 题解:SP20038 SNGLOOP1 - Easiest Loop 1
    数学题。根据题目中给出的等式:\[(2n+3)(p-1)+\frac{4}{5}[(p\cdot{S}_{n})-{S}_{m}]=2(m-n)\]变形:\[(10n+15)(p-1)+4[(p\cdot{S}_{n})-{S}_{m}]=10m-10n\]\[(10m+15)p-10m-15+4{S}_{n}p-4{S}_{m}=10m-10n\]\[(10m+15+4{S}_{n})p=10m+15+4{S}_{m}\]\[p=\frac{10m+15+4{S}......
  • 题解:P1701 [USACO19OPEN] Cow Evolution B
    这题的关键就在于能否将问题转化成集合之间是否有交集。首先,考虑一个我们无法形成进化树的例子,例如这样:31fly1man2flyman如果我们想根据这个输入构建一棵树,我们需要在根上分割A或B,但剩下的两个子树都需要有一条边来添加另一个特征。显然输出为"No"。如果我们输入......
  • 题解:SP4555 ANARC08F - Einbahnstrasse
    一道多源最短路问题,肯定用Floyd,还有个问题就是怎么处理输入。使用sscanf(edge+2,"%d",&cost);从edge的第三个字符开始读取边权,然后处理左右两侧的箭头即可。#include<bits/stdc++.h>usingnamespacestd;map<string,int>cn;intct;intq[1028];intadd_city(constch......