标签:font false 判断 处理 数值 name 移动 span 转化
题目大意:
有一个 0 ~ n+1 的数轴,Alice 站在 0 点处,Bob 站在 n+1 点处。在 1 ~ n 上各有着权值。 Alice 每次向右移动 1 格或两格 ,Bob 每次向左移动 1 格或 2 格(他们一定要移动),Alice 移动到 n+1 处停止,Bob 移动到 0 处停止,直到他们都停止的时候,此时若 Alice 所经过的数值总和大于 Bob 的数值总和,则 Alice 胜出,反则 Bob 胜出。Alice 先出手,两人足够聪明,走到的数值必须拿走,而走到过的数值不能再被拿走。
分析:
1、显然是博弈题。
2、dfs 枚举所有可能,当 Alice 出手时,有两种走法(走一步或两步)。比如 Alice 走一步后,枚举 Bob 走到的地方(也只有两种走法),然后判断是否 Bob 无论怎样走, 此时 Alice 必赢,则 “此刻 Alice 走一步” 为必胜态,因为若 Alice 走这一步之后, Bob 无论怎么操作都无法获胜,则此时为必胜态。
3、故枚举 Alice 的两次走法,假如此时 Alice 处于位置 x ,若此刻走到 u 可以使得自身处于必胜态,则返回 true ,告诉 dfs 的上一层中,走到 x 处可以转化为必胜态。
博弈点分析:假如此刻位置为 x ,现在两种走法可以使得 x 走到 u1 或者 u2。若 u1 与 u2 同时为必胜点,则 x 处也为必胜点;若 u1 是必胜点,u2 是必败点,则 x 处也为必胜点,因为 选手足够聪明,走到 x 处后会走到 u1 处,故 x 为必胜点;若 u1 与 u2 同为必败点,则 x 也为必败点。这就是为什么 必胜点可以转化为必败点或必胜点,而必败点只能转化为必败点。
细节处理:
1、此题不应该 vis 设为 bool 类型,因为走过的点会重复,不好判断。
2、最好走到临界点的时候特判(x==n+1 以及 y==0)。
代码如下:
#include<iostream> #include<algorithm> #include<string.h> using namespace std; int t,n; int a[18]; int tox[2]={1,2}; int toy[2]={-1,-2}; int vis[18]; bool dfs(int x,int y,int res,int ans){ if(x==n+1&&y==0) return res>ans; bool q; for(int i=0;i<2;i++){ q=true; int u,res1; if(x==n+1) u=x,res1=0; else{ u=x+tox[i]; if(u>n+1) continue; vis[u]++; res1=(vis[u]==2?0:a[u]); } for(int j=0;j<2;j++){ int v,ans1; if(y==0) v=y,ans1=0; else{ v=y+toy[j]; if(v<0) continue; vis[v]++; ans1=(vis[v]==2?0:a[v]); } bool w=dfs(u,v,res+res1,ans+ans1); if(y!=0) vis[v]--; if(!w) { q=false; break; } } if(x!=n+1) vis[u]--; if(q) return true; } return false; } int main() { scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); a[0]=a[n+1]=0; if(dfs(0,n+1,0,0)) printf("Alice\n"); else printf("Bob\n"); } }
标签:font false 判断 处理 数值 name 移动 span 转化
原文地址:https://www.cnblogs.com/Absofuckinglutely/p/12008807.html