博弈论

以前看见博弈论的题就直接跳过,直到上周河北省赛开始前瞅了两眼白书上的博弈论,发现博弈论不过是dp好像也不难哈.

今天刚好做到一个简单的博弈论

传送门

由于我当时对博弈论的了解仅限于博弈论就是dp,所以很兴奋的用dp提交了,然后就TLE在test12了

 

#include<bits/stdc++.h>
using namespace std;
int a[100010];
int dp[100010][5];
int main(){
	int n;
	scanf("%d", &n);
	for(int i = 0; i < n; i++) scanf("%d", &a[i]);
	for(int i = 0; i < n; i++){
		bool flag = true;
		for(int last = (i - 1 + n) % n; last != (i - 1 + n) % n || flag; last = (last - 1 + n) % n){
			if(last == (i - 1 + n) % n){
				dp[last][1] = 1; dp[last][0] = 0;
			}
			else{
				int pre = (last + 1) % n;
				if(a[last] == 1){
					dp[last][1] = dp[pre][0];
					dp[last][0] = dp[pre][1];
				} 
				else{
					dp[last][1] = 1;
					dp[last][0] = 0;
				}
			}
			flag =  false;
		}
		printf((dp[i][1] == 1) ? "First\n" : "Second\n");
	}
	return 0;
} 

很明显O(N*N)太大了,我灵机一动,直接改首尾的dp不就优化成O(N)了吗,然后就又WA在test10了

 

#include<bits/stdc++.h>
using namespace std;
int a[100010];
int dp[100010][5];
int main(){
	int n;
	scanf("%d", &n);
	for(int i = 0; i < n; i++) scanf("%d", &a[i]);
	for(int last = n - 1; last != -1; last--){
		if(last == n - 1){
			dp[last][1] = 1; dp[last][0] = 0;
		}
		else{
			int pre = (last + 1) % n;
			if(a[last] == 1){
				dp[last][1] = dp[pre][0];
				dp[last][0] = dp[pre][1];
			} 
			else{
				dp[last][1] = 1;
				dp[last][0] = 0;
			}
		}
	}
	printf((dp[0][1] == 1) ? "First\n" : "Second\n");
	int reverse = 0;
	for(int i = 1; i < n; i++){
		int llast = (i - 2 + n) % n, last = i - 1;
		if(a[llast] == 1) reverse = (1 - reverse);
		if(reverse){
			dp[i][1] = (1 - dp[i][1]); 
			dp[i][0] = (1 - dp[i][0]);
		} 
		printf((dp[i][1]  == 1) ? "First\n" : "Second\n");
	}
	return 0;
} 

冷静了一下,突然发现,这其实并不需要dp,只要谁先在>1的堆是先手谁就必胜。

所以只需要记录下>1堆的位置,每次只需要计算在当前位置前面的第一个堆与当前位置的距离就ojbk了。

由于是个环,莫名其妙的就想到了队列pop后push的骚操作hhh。

写完这段代码我感觉绝对要AC了,结果又WA在test7了

#include<bits/stdc++.h>
using namespace std;
queue <int > q; 
int main(){
	int n, x;
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) {
		scanf("%d", &x); 
		if(x > 1) q.push(i);
	}
	for(int i = 1; i <= n; i++){
		int u = q.front();
		if(i == u){
			printf("First\n");
			q.pop();
			q.push(u);
		}
		else{
			int dis = (u - i < 0 ? u - i + n : u - i);
			printf((dis % 2 == 1) ? "Second\n" : "First\n");
		} 
	}
	return 0;
}

怎么会WA呢??我瞟一眼题面,猛然发现,如果所有堆的size都为1的话,就不会有>1的堆,那么q就为空了,此处应加特判。

#include<bits/stdc++.h>
using namespace std;
queue <int > q; 
int main(){
	int n, x;
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) {
		scanf("%d", &x); 
		if(x > 1) q.push(i);
	}
	if(!q.empty()){
		for(int i = 1; i <= n; i++){
			int u = q.front();
			if(i == u){
				printf("First\n");
				q.pop();
				q.push(u);
			}
			else{
				int dis = (u - i < 0 ? u - i + n : u - i);
				printf((dis % 2 == 1) ? "Second\n" : "First\n");
			} 
		}
	}
	else for(int i = 1; i <= n; i++) printf((n % 2 == 1) ? "First\n" : "Second\n");
	return 0;
}

终于AC!罚时真令人绝望

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值