uva 141 The Spot Game

原题:
The game of Spot is played on an NxN board as shown below for N = 4. During the game, alternate players may either place a black counter (spot) in an empty square or remove one from the board, thus producing a variety of patterns. If a board pattern (or its rotation by 90 degrees or 180 degrees) is repeated during a game, the player producing that pattern loses and the other player wins. The game terminates in a draw after 2N moves if no duplicate pattern is produced before then.
Consider the following patterns:
这里写图片描述
If the first pattern had been produced earlier, then any of the following three patterns (plus one other not shown) would terminate the game, whereas the last one would not.

Input and Output

Input will consist of a series of games, each consisting of the size of the board, N (2 tex2html_wrap_inline180 N tex2html_wrap_inline180 50) followed, on separate lines, by 2N moves, whether they are all necessary or not. Each move will consist of the coordinates of a square (integers in the range 1..N) followed by a blank and a character +' or-’ indicating the addition or removal of a spot respectively. You may assume that all moves are legal, that is there will never be an attempt to place a spot on an occupied square, nor to remove a non-existent spot. Input will be terminated by a zero (0).

Output will consist of one line for each game indicating which player won and on which move, or that the game ended in a draw.

Sample input

2
1 1 +
2 2 +
2 2 -
1 2 +
2
1 1 +
2 2 +
1 2 +
2 2 -
0
Sample output

Player 2 wins on move 3
Draw
大意:
(来自lucky 猫)
放 石頭遊戲(The game of Spot)在一塊 NxN 的板子上進行,如下圖為N=4的板子。遊戲的玩法是兩個玩家輪流放一塊石頭在空的格子上,或是可以從板子上拿一塊石頭起來,遊戲的進行中可以發現,板子上 石頭的佈局會不斷變化,當一玩家排出已重複出現過的佈局時,他就算輸了這一局(一種佈局如果將之旋轉90度、180度、270度亦視為相同的佈局)。若在 2N步內未出現過相同的佈局就算和局。
Input

輸 入會有多組測試資料,一開始會給定板子的大小N (2 <= N <= 50),接下來會有 2N 個移步方式,當然也有可能2N步還沒走完就有人贏得了比賽。每一列會有一個座標位置,並以 + 或 - 來表示新增或移除一塊石頭。你可以假定所有的步驟都是合法的,也就是說,不會在空格子上拿走一塊石塊,也不會重複放置石頭在同一個位置上。輸入的最後會以 N=0 做結束。
Output

請輸出哪位玩家贏得了比賽,並在哪一步贏得比賽,若平手則輸出 draw。

#include<bits/stdc++.h>
using namespace std;

//fstream in,out;
map<string,bool> ms;
int n,m;
string span(string &ss)
{
    string t(n,'0');
    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<=m;j++)
        {
            int x=j;
            int y=m-i+1;
            t[(x-1)*m+y-1]=ss[(i-1)*m+j-1];
        }
    }
    return t;
}
void Move(int a,int b,char c,string &ss)
{
    if(c=='+')
        ss[m*a+b]='1';
    else
        ss[m*a+b]='0';
}

int main()
{
    ios::sync_with_stdio(false);
//  in.open("data.txt");
//  out.open("input.txt");
    while(cin>>m,m)
    {
        n=m*m;
        ms.clear();
        int ans=0,a,b;
        char c;
        string now(n,'0');
        string tmp1,tmp2,tmp3;
        for(int i=1;i<=m*2;i++)
        {
            cin>>a>>b>>c;
            if(ans==0)
            {
                Move(a-1,b-1,c,now);
            //  cout<<now<<endl;
                tmp1=span(now);
            //  cout<<tmp1<<endl;
                tmp2=span(tmp1);
            //  cout<<tmp2<<endl;
                tmp3=span(tmp2);
            //  cout<<tmp3<<endl;
                if(ms[now]||ms[tmp1]||ms[tmp2]||ms[tmp3])
                    ans=i;
                else
                    ms[now]=ms[tmp1]=ms[tmp2]=ms[tmp3]=true;
            }
        }
        if(ans==0)
            cout<<"Draw"<<endl;
        else
        {
            if(ans%2)
                cout<<"Player 2 wins on move "<<ans<<endl;
            else
                cout<<"Player 1 wins on move "<<ans<<endl;
        }
    }
//  in.close();
//  out.close();
    return 0;
}

解答:
最近在做毕设,但是还不能停下来做题~否则csdn上面持之以恒的小胸章就没了. =_= 所以打算先把uva上面100到199的做了,时间充裕的时候做几个难的。

题目很简单,每次用map记录之前走过的棋盘即可,棋盘旋转的时候要用到矩阵旋转的公式。
坐标的旋转公式是:
(x, y)绕(0, 0)顺时针转90度后坐标为(y, -x)
(x, y)绕(p, q)顺时针转90度,先把原点移到(p, q), (x-p, y-q)绕(0, 0)旋转90度后为(y-q, p-x)
最终结果(y-q+p, p-x+q)
矩阵的顺时针旋转公式要在y的坐标系上加1
即:
(y-q+p, p-x+q+1)
由于此题目是绕着中心旋转,所以p=q=n/2

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值