博弈论的一些理解
一、起因以及一些理解
之前在某个可怕的比赛中看到了博弈论的签到题,但是由于三个人没有一个学过博弈论以至于强行放弃的事故发生。我决定立刻,马上开坑博弈论专题。
首先递归的定义决胜点和绝败点。
对于所有目前我看到了的博弈游戏,都可以使用如下方式进行定义所有局面(从而至少可以暴力搜索):
1、对于所有局面(游戏的某个状态),要么是决胜点,要么是绝败点。
2、决胜点:在当前局面,先手必然胜利。
3、绝败点:在当前局面,先手必然失败。
决胜点绝败点的性质:
1、决胜点:可以立即取胜或者至少有一条路到达绝败点(在完成当前选择之后,对手将成为新的先手)。
2、绝败点:已经输掉比赛或者所有合法路径都通往决胜点(在完成当前选择之后,对手将成为新的先手)。
二、分类以及相关题目
-
动态博弈
POJ1678
UVA3668 -
巴士博弈
-
威佐夫游戏
-
尼姆游戏(nimanti_nim)
三、题解
1、POJ1678
首先分析题目,可以发现,a,b的具体大小大于0,则这意味着每次选取的时候后一个数必然大与前一个数字。因此具有单调性,可以先将数组排序。(按照这个道理其实可以去除掉所有小于a的数字)
其次,首先假设dp[i]代表当先手面临arr[i]时的最优选择,则,应当认为,每次状态转移的目的实际上是在替后手做决策——在当前状态选取最小收益的点作为后续选择。
最后考虑特殊点——游戏结束点,dp[i]应当为arr[i]本身。

#include<iostream> #include<stdlib.h> #include<stdio.h> #include<math.h> #include<string.h> #include<algorithm> #include<vector> #include<set> #include<map> #include<queue> using namespace std; #define ll long long const ll MAXN=100233; const ll INF = (ll)1<<40; ll arr[MAXN]; ll dp[MAXN]; ll n,a,b; void init() { cin>>n>>a>>b; for(int i=0;i<n;++i) cin>>arr[i]; sort(arr,arr+n); for(int i= n-1;i>=0;--i) { dp[i] = INF; for(int j=i+1;j<n;++j) { if(arr[j]<arr[i]+a)continue; if(arr[j]>arr[i]+b)break; dp[i] = min(arr[i] - dp[j],dp[i]); } if(dp[i] == INF)dp[i] = arr[i]; } ll ans = -INF; for(int i=0;i<n;++i) { if(arr[i] < a)continue; if(arr[i] > b)break; ans = max(dp[i],ans); } if(ans == -INF)ans = 0; cout<<ans<<" "; } int main() { int t; cin>>t; while(t--) init(); return 0; }