POJ 2706 Connect

Connect

Description

Figure 1Figure 2Figure 3aFigure 3bFigure 4

Your task is to decide if a specified sequence of moves in the board game Twixt ends with a winning move. 

In this version of the game, different board sizes may be specified. Pegs are placed on a board at integer coordinates in the range [0, N]. Players Black and White use pegs of their own color. Black always starts and then alternates with White, placing a peg at one unoccupied position (x,y). Black's endzones are where x equals 0 or N, and White's endzones are where y equals 0 or N. Neither player may place a peg in the other player's endzones. After each play the latest position is connected by a segment to every position with a peg of the same color that is a chess knight's move away (2 away in one coordinate and 1 away in the other), provided that a new segment will touch no segment already added, except at an endpoint. Play stops after a winning move, which is when a player's segments complete a connected path between the player's endzones. 

For example Figure 1 shows a board with N=4 after the moves (0,2), (2,4), and (4,2). Figure 2 adds the next move (3,2). Figure 3a shows a poor next move of Black to (2,3). Figure 3b shows an alternate move for Black to (2,1) which would win the game. 

Figure 4 shows the board with N=7 after Black wins in 11 moves: 
(0, 3), (6, 5), (3, 2), (5, 7), (7, 2), (4, 4), (5, 3), (5, 2), (4, 5), (4, 0), (2, 4). 

Input

The input contains from 1 to 20 datasets followed by a line containing only two zeroes, "0 0". The first line of each dataset contains the maximum coordinate N and the number of total moves M where 3 < N < 21, 4 < M < 250, and M is odd. The rest of the dataset contains a total of M coordinate pairs, with one or more pairs per line. All numbers on a line will be separated by a space. M being odd means that Black will always be the last player. All data will be legal. There will never be a winning move before the last move.

Output

The output contains one line for each data set: "yes" if the last move is a winning move and "no" otherwise.

Sample Input

4 5
0 2 2 4 4 2 3 2 2 3
4 5
0 2 2 4 4 2 3 2 2 1
7 11
0 3 6 5 3 2 5 7 7 2 4 4
5 3 5 2 4 5 4 0 2 4
0 0

Sample Output

no
yes
yes
 
/* 题目大意
   题意描述没看清楚,看了题解之后更模糊了,所以打算写一个正规一点的题意.
   题目的大意是给一个n*n的棋盘,但由于存在0点所以真正的棋盘点数有(n+1)*(n+1).
   然后再依次给出m组棋子的坐标,黑棋先手。然后在棋盘上放下一个棋子的前提是这个点上之前没有棋子,相同颜色的棋子可以相互连接起来,连接的方式是按照“日”字的八个方向,也就是说,如果这个棋子的周围八个方向上有棋子的话,就可以连接起来了放一颗棋子也许会出现多条线段可连,那就全部连上.
   关键点是如果黑棋在棋盘上可以在横方向上(即x轴方向)一直连接到n,判赢。或者相反,白棋在棋盘上可以在纵方向上(即y轴方向)一直连接到n,判赢.
   连接的时候注意不管是黑线段还是白线段一律不可以相交.
   最后的结果意思是问在m组棋子都放完时有没有分出胜负,如果在所有棋子放完之前分出胜负了,输出yes,否则就是no.
*/
/*解题思路
  先把所有的棋子坐标都存起来,初始化棋盘,一个一个的放棋子,注意标记棋子是黑还是白。放的时候把这个棋子可以连接的所有线段都连接上。每放完一个棋子就判断一下棋盘最左边和最下边有没有出现棋子,如果出现了棋子,就直接bfs去搜,搜到为n的情况,跳到最后,否则继续放棋子。
*/
<pre name="code" class="html">#include <algorithm>
#include <iostream>
#include <numeric>
#include <cstring>
#include <iomanip>
#include <string>
#include <vector>
#include <cstdio>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
#include <set>
#define LL long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int M = 300;
const double esp = 1e-8;
const int INF = 0x3f3f3f3f;
const double PI = 3.141592653589793;
using namespace std;

struct Point{
    int x,y;
    bool friend operator ==(Point a,Point b){
        return (a.x == b.x && a.y == b.y);
    }
}Point_arr[300];

struct Line{
    Point a,b;
}arr[250*250];

int n,m,top;
int Map[30][30];
int dx[] = {-1,-2,-2,-1,1,2,2,1};
int dy[] = {-2,-1,1,2,2,1,-1,-2};
bool vis[30][30];
bool flag;
int xmult(Point p1,Point p2,Point p){
    return (p1.x-p.x)*(p2.y-p.y) - (p2.x-p.x)*(p1.y-p.y);
}
//判断两线段是否相交
bool isx(Line u,Line v){
    return (max(u.a.x,u.b.x) >= min(v.a.x,v.b.x)) &&
           (max(v.a.x,v.b.x) >= min(u.a.x,u.b.x)) &&
           (max(u.a.y,u.b.y) >= min(v.a.y,v.b.x)) &&
           (max(v.a.y,v.b.x) >= min(u.a.y,u.b.y)) &&
           (xmult(u.a,v.a,u.b)*xmult(u.a,u.b,v.b) > esp) &&
           (xmult(v.a,u.a,v.b)*xmult(v.a,v.b,u.b) > esp);
}
//加一颗棋子
void build(int x,int y,int type){
    if(Map[x][y] == -1){
        Map[x][y] = type;
        for(int i=0;i<8;i++){
            int nowx = x + dx[i];
            int nowy = y + dy[i];
            if(nowx >=0 && nowx <= n && nowy >= 0 && nowy <= n && Map[nowx][nowy]!=-1 && Map[nowx][nowy] == Map[x][y]){
                Line ant;ant.a = {x,y};ant.b = {nowx,nowy};
                bool flag = true;
                for(int j=0;j<top;j++){
                    if(isx(arr[j],ant)){
                        flag = false;
                        break;
                    }
                }
                if(flag){
                    arr[top++] = ant;
                }
            }
        }
    }
}
//判断线段有没有被连接起来过
bool f(int x,int y,int u,int v){
    for(int i=0;i<top;i++){
        if((arr[i].a.x == x && arr[i].a.y == y && arr[i].b.x == u && arr[i].b.y == v) ||
           (arr[i].b.x == x && arr[i].b.y == y && arr[i].a.x == u && arr[i].a.y == v) )
        return true;
    }
    return false;
}
//黑棋的bfs
void b_bfs(int y){
    memset(vis,false,sizeof(vis));
    queue<Point>Q;
    Q.push({0,y});
    vis[0][y] = true;
    while(!Q.empty()){
        Point ant = Q.front();Q.pop();
        if(ant.x == n){
            flag = true;
            break;
        }
        for(int i=0;i<8;i++){
            int nowx = ant.x + dx[i];
            int nowy = ant.y + dy[i];
            if(nowx >=0 && nowx <= n && nowy >= 0 && nowy <= n && !vis[nowx][nowy] && Map[nowx][nowy]!=-1 && f(ant.x,ant.y,nowx,nowy)){
                vis[nowx][nowy] = true;
                Q.push({nowx,nowy});
            }
        }
    }
}
//白棋的bfs
void w_bfs(int x){
    memset(vis,false,sizeof(vis));
    queue<Point>Q;
    Q.push({x,0});
    vis[x][0] = true;
    while(!Q.empty()){
        Point ant = Q.front();Q.pop();
        if(ant.y == n){
            flag = true;
            break;
        }
        for(int i=0;i<8;i++){
            int nowx = ant.x + dx[i];
            int nowy = ant.y + dy[i];
            if(nowx >=0 && nowx <= n && nowy >= 0 && nowy <= n && !vis[nowx][nowy] && Map[nowx][nowy]!=-1 && f(ant.x,ant.y,nowx,nowy)){
                vis[nowx][nowy] = true;
                Q.push({nowx,nowy});
            }
        }
    }
}
int main(){
    while(~scanf("%d %d",&n,&m) && (n||m)){
        top = 0;
        flag = false;
        memset(Map,-1,sizeof(Map));
        for(int i=1;i<=m;i++)
            scanf("%d %d",&Point_arr[i].x,&Point_arr[i].y);
        for(int i=1;i<=m;i++){
            build(Point_arr[i].x,Point_arr[i].y,i%2); //黑1 白2
            for(int j=0;j<=n;j++){
                if(Map[0][j]!=-1){
                    b_bfs(j);
                }
                if(flag) break;
            }
            if(flag) break;
            for(int j=0;j<=n;j++){
                if(Map[j][0]!=-1){
                    w_bfs(j);
                }
            }
        }
        if(flag)
            printf("yes\n");
        else
            printf("no\n");
    }
    return 0;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值