[POJ1082&POJ2348&POJ1067&POJ2505&POJ1960]简单博弈题总结

  鉴于时间紧张...虽然知道博弈是个大课题但是花一个上午时间已经极限了...

  希望省选过后再回过头来好好总结一遍吧。

  接下来为了看着顺眼一点...还是按照难度顺序吧



 

POJ1082

  一道最简单的博弈题,只需要DP就可以过。

  在这道题里我尽情展示了多函数多过程的代码风格。。

program poj1082;
const u:set of 0..20=[1,3,5,7,8,10,12];
var n,i,x,y,z:longint;
    f:array[1900..2002,1..12,1..31]of boolean;

function leap(x:longint):boolean;
begin
    if x mod 100=0 then
    begin
        if x mod 400=0 then exit(true);
    end else
    begin
        if x mod 4=0 then exit(true);
    end;
    exit(false);
end;

function exist(x,y,z:longint):boolean;
begin
    if y in u then
        begin
                if z<32 then exit(true);
        end else
    begin
        if y<>2 then
        begin
            if z>30 then exit(false) else exit(true);
        end else
        begin
            if (z<29)or(leap(x)and(z=29)) then exit(true);
        end;
    end;
    exit(false);
end;

function next_day(x,y,z:longint):boolean;
begin
    inc(z);
    if not exist(x,y,z) then
    begin
        inc(y);z:=1;
    end;
    if y>12 then
    begin
        inc(x);y:=1;
    end;
    exit(f[x,y,z]);
end;

function next_month(x,y,z:longint):boolean;
begin
    inc(y);
    if y>12 then
    begin
        inc(x);y:=1;
    end;
    if not exist(x,y,z) then exit(false);
    exit(f[x,y,z]);
end;

procedure solve;
var i,j,k:longint;
    flag:boolean;
begin
    fillchar(f,sizeof(f),false);
    for i:=2001 downto 1900 do
        for j:=12 downto 1 do
            for k:=31 downto 1 do if exist(i,j,k) then
            begin
                flag:=true;
                if next_day(i,j,k) then flag:=false;
                if next_month(i,j,k) then flag:=false;
                f[i,j,k]:=flag;
            end;
end;

begin
    assign(input,‘poj1082.in‘);reset(input);
    readln(n);
    solve;
        for i:=1 to n do
    begin
        readln(x,y,z);
        if f[x,y,z] then writeln(‘NO‘) else writeln(‘YES‘);
    end;
end.


POJ2960

  简单的SG函数的运用。

program poj2960;
const maxn=10010;maxm=110;
var sizes,i,n,m,x,ans,j:longint;
    s:array[-1..maxm]of longint;
    w:array[-1..maxn]of longint;
    vis:array[-1..2*maxn,-1..maxm]of boolean;

procedure calc_SG;
var i,j:longint;
begin
    fillchar(vis,sizeof(vis),false);
    for i:=0 to maxn do
    begin
        for j:=0 to maxm do if not vis[i,j] then break;
        w[i]:=j;
        for j:=1 to sizes do vis[i+s[j],w[i]]:=true;
    end;
end;

begin
    //assign(input,‘poj2960.in‘);reset(input);
    //assign(output,‘poj2960.out‘);rewrite(output);
    read(sizes);
    while sizes<>0 do
    begin
        for i:=1 to sizes do read(s[i]);readln;
        calc_SG;
        readln(m);
        for i:=1 to m do
        begin
            ans:=0;
            read(n);
            for j:=1 to n do
            begin
                read(x);
                ans:=ans xor w[x];
            end;
                        if ans>0 then write(‘W‘) else write(‘L‘);
            readln;
        end;
                writeln;
        read(sizes);
    end;
end.


POJ2505

  题面很亲切,就是不停乘上2~9之间的一个数,超过了某个数n即算赢。

  依稀记得去年暑假做过这道题,当时应该数据比较弱是直接DP过的...

  然后先还是无脑DP,然后输出发现了很神奇的规律...

  2~9 先手赢

  10~18 后手赢

  19~162 先手赢

  163~324 后手赢

  ...

  想来其实也并无道理,但是找规律无疑是最快捷的方法了。

program poj2505;
var x:int64;

function solve(x:int64):boolean;
var k:int64;
begin
    k:=1;
    while true do
    begin
        k:=k*9;
        if x<=k then exit(true);
        k:=k*2;
        if x<=k then exit(false);
    end;
end;

begin
    while not eof do
    begin
        readln(x);
        if solve(x) then writeln(‘Stan wins.‘) else writeln(‘Ollie wins.‘);
    end;
end.


POJ2348

  这道题我的思考出现了一点问题...

  刚开始认为,对于每一个(x,y)到(y,x mod y)的过程,都可以看做是一场Nim游戏

  然后石子的个数就是x div y的个数

  自己觉得非常有道理,然后就SG敲起来了...

  发现怎么都过不去,和标算对拍了之后发现是这样的...

  Nim游戏你可以任意选一堆石子开始,而这道题是从大减到小

  也就是强制必须先从第一堆石子里取完才能从第二堆取

  于是就不可以用SG函数了

  继续看,发现如果当x div y=1的时候,只有一种选择

  而当x div y>=2的时候,起码有两种选择而且显然是可以交换和对手的身份的

  这种情况下就是必胜的。

  然后辗转相除套一个特判就可以AC啦

program poj2348;
var tem,x,y:int64;

function solve(x,y:int64):boolean;
begin
    if y=0 then exit(false);
    if x div y>=2 then exit(true);
    exit(not solve(y,x mod y));
end;

begin
    assign(input,‘poj2348.in‘);reset(input);
    readln(x,y);
    while (x<>0)or(y<>0) do
    begin
        if x<y then
        begin
            tem:=x;x:=y;y:=tem;
        end;
        if solve(x,y) then writeln(‘Stan wins‘)
        else writeln(‘Ollie wins‘);
                readln(x,y);
    end;
end.


POJ1067 

  一道裸的威佐夫博弈...

  两堆石子中可以在任意一堆中取若干个,也可以在两堆中取相同数量个。

  奇异状态(x,y)满足:

    x=a[i],y=a[i]+i

  而a[i]=i*(sqrt(5)-1)/2+i;

  非奇异状态为必胜状态,反之必败。

  我是用二分来实现x=a[i]这一步的查找的...

  (刚开始非常sx的用了1.618后来发现x<=10^9,乘到后面显然精度不够,然后copy来了一堆长的黄金分割数,但是忘记把小数点前改1了...然后一直WA。发现其实就是(sqrt(5)-1)/2...既简单不用背有精确度高...真是初三内容都还给李老师了...连黄金分割都忘掉了QAQ)

program poj1067;
const INF=1000000000;
      num=(sqrt(5)-1)/2+1;
var x,y,tem:int64;

function find(x:int64):int64;
var L,R,mid,tem:int64;
begin
    L:=0;R:=INF;
    while L<=R do
    begin
        mid:=(L+R) >> 1;
        tem:=trunc(num*mid);
        if x=tem then exit(mid);
        if x<tem then R:=mid-1 else L:=mid+1;
    end;
    exit(-1);
end;

begin
    while not eof do
    begin
        readln(x,y);
        if x>y then
        begin
            tem:=x;x:=y;y:=tem;
        end;
        tem:=find(x);
        if (tem=-1)or(tem+x<>y) then writeln(1) else writeln(0);
    end;
end.
        
时间: 2024-08-13 11:34:13

[POJ1082&POJ2348&POJ1067&POJ2505&POJ1960]简单博弈题总结的相关文章

ACM: NBUT 1107 盒子游戏 - 简单博弈

NBUT 1107  盒子游戏 Time Limit:1000MS     Memory Limit:65535KB     64bit IO Format: Practice Appoint description:  System Crawler  (Aug 13, 2016 10:35:29 PM) Description 有两个相同的盒子,其中一个装了n个球,另一个装了一个球.Alice和Bob发明了一个游戏,规则如下:Alice和Bob轮流操作,Alice先操作每次操作时,游戏者先看看

HDU 5135 Little Zu Chongzhi&#39;s Triangles(简单水题)

题目链接: 戳我 题目大意: 给一堆 木棍,用这些木棍组成三角形,要组成的所有的三角形的面积和最大,不一定要用完所有的木棍. 样例解释: 3 //三个棍子 1 1 20   // 每个棍子的长度,自然,这三个棍子不可能组成三角形,故输出 0.00 7          // 7个棍子 3 4 5 3 4 5 90 // 组成两个三角形(3, 3 4)和(4, 4, 5),面积和即为13.64 0   // 输出 0 退出 解题思路: 本来不想写题解的,因为太水了,,,,,,, 可是看到 谷歌搜出

POJ 2545+2591+2247+1338简单水题

[题意简述]:就是有这样的一个序列,就拿当p1 = 2,p2 = 3, p3 = 5,来举例,由这三个数为基准组成的序列是: 2,3,4,5,6,8,9,10,12--现在给你这个序列数组的下标,让你求得这个数组中,这个下标里的数是多少. [分析]:2,3,4,5,6,8,9,10,12--这个序列式由2,3,5这三个数生成的,具体如何生成,就是: 详见代码: 这里以POJ2545为例: //弄清其中的逻辑关系,可以从最简单的2,3,5试着做起! #include<iostream> #inc

FZU Problem 2034 Password table (简单模拟题)

这种简单题做了好长时间,我是不是有点逗? 地址:http://acm.fzu.edu.cn/problem.php?pid=2034 不解释了,自己看吧,练手的好题 上个代码吧 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <stdio.h> #include <string.h> #include <stdlib.h>

HDU 1846 Brave Game (简单博弈)

HDU 1846 Brave Game (简单博弈) ACM 题目地址: HDU 1846 Brave Game 题意: 中文. 分析: 博弈入门. 如果n=m+1,因为最多取m个,所以先拿的人拿多少个,后拿的人能全拿走. 所以判断n%(m+1)即可. 代码: /* * Author: illuz <iilluzen[at]gmail.com> * File: 1846.cpp * Create Date: 2014-09-20 10:05:26 * Descripton: game */ #

2014 HDU多校弟九场I题 不会DP也能水出来的简单DP题

听了ZWK大大的思路,就立马1A了 思路是这样的: 算最小GPA的时候,首先每个科目分配到69分(不足的话直接输出GPA 2),然后FOR循环下来使REMAIN POINT减少,每个科目的上限加到100即可 算最大GPA的时候,首先每个科目分配到60分,然后FOR循环下来使REMAIN POINT减少,每个科目的上限加到85即可,如果还有REMAIN POINT,就FOR循环下来加到100上限即可 不会DP 阿 QAQ 过段时间得好好看DP了  =  = 于是默默的把这题标记为<水题集> //

[简单博弈] hdu 1525 Euclid&#39;s Game

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1525 Euclid's Game Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1832    Accepted Submission(s): 808 Problem Description Two players, Stan and

hdu 4493 Tutor(简单处理题)

http://acm.hdu.edu.cn/showproblem.php?pid=4493 题意是输入12个数据,让你求平均值,但是要去除尾零,就像100.00只要输出100 其实这题有点不严密,像这组数据 2 100.995 100.995 100.995 100.995 100.995 100.995 100.995 100.995 100.995 100.995 100.995 100.995 输出100,其他可以过的输出100.10以及101都可以 用自己的方法死活不可以过,上网搜了一

hdu 2999 sg函数(简单博弈)

Stone Game, Why are you always there? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 393    Accepted Submission(s): 132 Problem Description "Alice and Bob are playing stone game...""E