HDU 1079 Calendar Game(NP状态交替)

It's a easy Game Theory......

网上是这么说的,思想倒是不难,但操作起来自己遇到些麻烦。作为一只博弈论入门级别弱脊,于是来写一篇题解总结一下吧,虽然是自己模拟出来的,但中间还是遇到了一丝丝麻烦。大家都知道,所有的后继状态是N状态的某个状态叫做P状态,后继状态中存在一个或多个状态为P状态的某个状态叫做P状态,哎,当时写的时候不知道咋想的,写×了,于是WA了好多次,但今天不仅AC了这道题,也学了若干时间前想巩固使用的一个知识点,那就是C语言的输出数据到文件,庆祝!


先说下题意吧,网上搜的...

从当前日期,玩家可以移动到下一天或下月的同一天。当在下一个月中不存在同一天,则玩家只能移动到下一天。例如,从1924年12月19日,你可以移动到1924年12月20日(下一天),或1925年2月19日(下个月的同一天)。然而,2001年1月31日,你只可以移动到2001年2月1日,因为2001年2月31日是无效的。玩家赢得比赛,仅当他/她到底操作之后到达的日期2001年11月4日。如果一个玩家移动到日期2001年11月4号之后,则算他/她输了比赛。


思路是,(2001 , 11 , 4)是个必败点,能到(2001, 11 , 4)的是必胜点,由时间从后向前推。


网上的大神们是通过打表找到了规律,不过自己真心不想找......那么多数,得扒拉多长时间啊!算了,还是我比较菜的原因。。然后我就用了一个三维数组存的点,然后把所有点的状态都求出来了,打了个表想找规律,数据真心多,看了一小会就不想看了,于是不找规律了,直接交,本以为会TLE的呢,没想到AC了,又暴露了自己复杂度没掌握好的水平了,哎。

下面是我的代码,

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
using namespace std;
int a[2005][15][35];
FILE *fp;
int check(int a, int b){
	int k = 0;
	if(a%4==0 && a%100!=0 || a%400==0&&a%100==0) k = 1;
	switch(b){
		case 1: return 31;
		case 2: if(k) return 29; else return 28;
		case 3: return 31;
		case 4: return 30;
		case 5: return 31;
		case 6: return 30;
		case 7: return 31;
		case 8: return 31;
		case 9: return 30;
		case 10: return 31;
		case 11: return 30;
		case 12: return 31;
	}
}
void getSG(int x, int y, int z){
	int i, j, l, k, f, c, flag = 1, t;
	for(i = 2001; i >= x; --i)
	for(j = 12; j >= 1; --j)
	for(l = check(i, j); l >= 1; --l){
		if(flag) j = 10, l = 4, flag = 0;
		
		c = i, k = j+1, t = 1;
		if(k == 13) k = 1, ++c;
		if(l <= check(c, k)) if(a[c][k][l] == 0) t = 0;
		
		if(t){
			c = i, k = j, f = l+1;
			if(f > check(i, j)) f = 1, ++k;
			if(k == 13) k = 1, ++c; 
			if(a[c][k][f] == 1) a[i][j][l] = 0;
			else a[i][j][l] = 1;
		}
		else a[i][j][l] = 1;
		fprintf(fp, "%d-%d-%d--- = %d\n", i, j, l, a[i][j][l]);
		if(i == x && j == y && l == z) return;
	}
}
int main(){
	int t, ak, bk, ck;
	memset(a, -1, sizeof a);
	cin >> t;
	for(int i = 5; i <= 31; ++i){
		if(i%2) a[2001][10][i] = 0;
		else a[2001][10][i] = 1;
	}
	a[2001][11][1] = a[2001][11][3] = 1;
	a[2001][11][2] = a[2001][11][4] = 0;
	fp = fopen("data.txt", "w");
	getSG(1900, 1, 1);
	fclose(fp);
	while(t--){
		cin >> ak >> bk >> ck;
		if(a[ak][bk][ck]) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
	return 0;
}

还有一个自己蛮奇怪的事情,会什么不删输出文件那些东西还会AC? 算了,还是因为菜...

然后规律是,不管闰年还是平年,只要月数+天数是个偶数,或者是9月30或者11月30,是必胜点,

其他位置为必败点。

#include <bits/stdc++.h>
using namespace std;
int main(){
	ios::sync_with_stdio(0);
	int t, n, y, r;
	cin >> t;
	while(t--){
		cin >> n >> y >> r;
		if((y+r)%2 == 0 || y == 9 && r == 30 || y == 11 && r == 30)
			cout << "YES" << endl;
		else cout << "NO" << endl;
	}
	return 0;
}

继续加油!~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值