ACM训练日记—3月21日

        这次就整理下关于Nim博弈的新收获和之前比赛的一道经典问题,有时间的话在总结下hiho上刷到的好题。(感觉hiho上的题越来越难刷了,但每天还是三人勉强维持不到10题)。

       Nim博弈新收获

参考:http://blog.csdn.net/strangedbly/article/details/51137432

1.把原游戏分解成多个独立的子游戏,则原游戏的SG函数值是它的所有子游戏的SG函数值的异或。
       即sg(G)=sg(G1)^sg(G2)^...^sg(Gn)。
2.分别考虑没一个子游戏,计算其SG值。
     SG值的计算方法:(重点)
(1).可选步数为1~m的连续整数,直接取模即可,SG(x) = x % (m+1);
(2).可选步数为任意步,SG(x) = x;
(3).可选步数为一系列不连续的数,用模板计算。

      感觉对于博弈论我还是没法把理解上升上去,看过大多数资料都是直接说有这个定理,sg函数怎么用,可我还是自己无法证明出来为什么sg函数可以用于博弈,为什么上面定理一就是这么求。

但是如果单纯为了做A题的话目前还算太不困难。

       hiho#1173 : 博弈游戏·Nim游戏·三

      在这一次游戏中Alice和Bob决定在原来的Nim游戏上增加一条规则:每一次行动时,不仅可以选择一堆取走任意数量的石子(至少取1颗,至多取出这一堆剩下的所有石子),还可以选择将一堆石子分成两堆石子,但并不取走石子。比如说有一堆石子为k个,当Alice或者Bob行动时,可以将这一堆石子分成两堆分别为x,y。满足x+y=k,x,y>0。那么增加了这一条规则后,在Alice总先手的情况下,请你根据石子堆的情况判断是Alice会获胜还是Bob会获胜?

      其实这道题就用了上面一条定理1,然后打表算出所有sg值输出就可以了。

using namespace std;
int vis[20005];
int sg[20005];
void init()
{
    for(int i=1;i<=20000;i++)
    {
        memset(vis,0,sizeof(vis));
        for(int j=0;j<i;j++)
        {
            int k;
            k=sg[j]^sg[i-j];
            vis[sg[j]]=1;
            vis[k]=1;
        }
        for(int j=0;j<=20000;j++)
        {
            if(!vis[j])
            {
                sg[i]=j;
                break;
            }
        }
    }
}
int main()
{
    memset(sg,0,sizeof(sg));
    init();
    int n,x;
    int ans=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        ans^=sg[x];
    }
    if(!ans) cout<<"Bob"<<endl;
    else cout<<"Alice"<<endl;
}

       牛客练习赛13  F题  m皇后

       在一个n*n的国际象棋棋盘上有m个皇后。一个皇后可以攻击其他八个方向的皇后(上、下、左、右、左上、右上、左下、右下)。对于某个皇后,如果某一个方向上有其他皇后,那么这个方向对她就是不安全的。对于每个皇后,我们都能知道她在几个方向上是不安全的。现在我们想要求出t0,t1,...,t8,其中ti表示恰有i个方向是"不安全的"的皇后有多少个。

       其实这个题也算经典问题八皇后之一,我的思路其实也是映射,先利用结构体储存点,然后按照优先y和x的排下序,接下来依次处理,遍历过的点映射到一个数组,分别做i+j,i-j+n....还是看代码吧

来自:https://www.cnblogs.com/ACRykl/p/8586235.html

#include<cstdio>
#include<algorithm>
using namespace std;
struct Node

{
    int x,y,num;
}a[100100];
int sum[100100];
int t[10];
int cmp1(Node A,Node B)
{if(A.x==B.x) return A.y<B.y;return A.x<B.x;}
int cmp2(Node A,Node B)
{if(A.y==B.y) return A.x<B.x;return A.y<B.y;}
int cmp3(Node A,Node B)
{if(A.x+A.y==B.x+B.y) return A.x<B.x;return A.x+A.y<B.x+B.y;}
int cmp4(Node A,Node B)
{if(A.x-A.y==B.x-B.y) return A.x<B.x;return A.x-A.y<B.x-B.y;}
int main()
{
    int m;
    scanf("%d%d",&m,&m);
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&a[i].x,&a[i].y);
        a[i].num=i;
    }
    
    sort(a,a+m,cmp1);
    for(int i=1;i<m;i++) 
        if(a[i-1].x==a[i].x) 
            {sum[a[i-1].num]++;sum[a[i].num]++;}
    sort(a,a+m,cmp2);
    for(int i=1;i<m;i++) 
        if(a[i-1].y==a[i].y) 
            {sum[a[i-1].num]++;sum[a[i].num]++;}
    sort(a,a+m,cmp3);
    for(int i=1;i<m;i++) 
        if(a[i-1].x+a[i-1].y==a[i].x+a[i].y) 
            {sum[a[i-1].num]++;sum[a[i].num]++;}
    sort(a,a+m,cmp4);
    for(int i=1;i<m;i++) 
        if(a[i-1].x-a[i-1].y==a[i].x-a[i].y) 
            {sum[a[i-1].num]++;sum[a[i].num]++;}
    
    for(int i=0;i<m;i++)
    t[sum[i]]++;
    for(int i=0;i<8;i++) printf("%d ",t[i]);
    printf("%d\n",t[8]);
    return 0;
}

       比较晚了,先整理到这吧。下次再整理hiho上那个区间合并

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值