poj 2706 Connect

Connect
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 1349 Accepted: 444

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

Source

提示

题意:

给出n*n的矩阵(3<n<21),之后再给出m个点(4<m<250),黑子先手,白子后手,它们按照坐标顺序依次放入棋盘(矩阵)中,并且它们会以象棋中马的走法进行相互连线,如果之前的连线阻断了当前连线,那么这条线将不存在。那么黑子能否在最后一步时完成从最左端到达最右端。

思路:

输入输出都没什么问题,主要是线段判交,这条线段干脆就和其他线段直接用计算几何的线段判交就行了,只是不包括端点。

示例程序

Source Code

Problem: 2706		Code Length: 3132B
Memory: 604K		Time: 16MS
Language: GCC		Result: Accepted
#include <stdio.h>
#include <string.h>
struct point
{
    int x,y;
}p[250];
struct
{
    int color,id;
}map[21][21];				//棋盘各个棋子的编号以及颜色
int n,m,w[250][250],walk[8][2]={{-2,-1},{-2,1},{-1,-2},{-1,2},{1,-2},{1,2},{2,-1},{2,1}};	//w数组记录连线情况
int cross(struct point a,struct point b,struct point o)
{
    return (a.x-o.x)*(b.y-o.y)-(a.y-o.y)*(b.x-o.x);
}
int judge(struct point a,struct point b,struct point c,struct point d)
{
    return cross(a,c,b)*cross(a,b,d)>0&&cross(c,a,d)*cross(c,d,b)>0;
}
int bfs()
{
    int v[250],q[125],i,i1,f,top;
    for(i=0;n>=i;i++)					//枚举最左边的点
    {
        if(map[0][i].color!=1)
        {
            continue;
        }
        memset(v,0,sizeof(v));
        f=0;
        top=0;
        q[top]=map[0][i].id;
        top++;
        v[q[f]]=1;
        while(f<top)
        {
            if(p[q[f]].x==n)
            {
                return 1;
            }
            for(i1=0;m>i1;i1++)
            {
                if(v[i1]==0&&w[q[f]][i1]==1)
                {
                    q[top]=i1;
                    top++;
                    v[i1]=1;
                }
            }
            f++;
        }
    }
    return 0;
}
void f(int x,int y,int color)
{
    int i,i1,i2,x1,y1,pos,pos1;
    struct point a,b;
    pos=map[x][y].id;
    for(i=0;8>i;i++)
    {
        x1=x+walk[i][0];
        y1=y+walk[i][1];
        if(x1>=0&&y1>=0&&x1<=n&&y1<=n&&map[x1][y1].color==color)	//颜色是否一样且不超边界
        {
            pos1=map[x1][y1].id;
            a.x=x;
            a.y=y;
            b.x=x1;
            b.y=y1;
            for(i1=0;m>i1;i1++)
            {
                for(i2=i1+1;m>i2;i2++)
                {
                    if(w[i1][i2]==0)				//未连线
                    {
                        continue;
                    }
                    if(judge(a,b,p[i1],p[i2])==1)			//判断是否相交
                    {
                        break;
                    }
                }
                if(i2!=m)
                {
                    break;
                }
            }
            if(i1==m)					//没有线段阻挡,连线
            {
                w[pos][pos1]=1;
                w[pos1][pos]=1;
            }
        }
    }
}
int main()
{
    int i,flag;
    scanf("%d %d",&n,&m);
    while(n!=0||m!=0)
    {
        flag=0;
        memset(map,-1,sizeof(map));
        memset(w,0,sizeof(w));
        for(i=0;m>i;i++)
        {
            scanf("%d %d",&p[i].x,&p[i].y);
            if(flag==-1)				//不是最后一步就达成目标,后面的数据不做处理
            {
                continue;
            };
            map[p[i].x][p[i].y].id=i;
            if(i%2==0)					//黑子
            {
                map[p[i].x][p[i].y].color=1;
                f(p[i].x,p[i].y,1);			//黑子连线
            }
            else					//白子
            {
                map[p[i].x][p[i].y].color=2;
                f(p[i].x,p[i].y,2);			//白子连线
            }
            if(bfs()==1)				//当前状态是否能达成目标
            {
                if(i!=m-1)				//不是最后一步的情况
                {
                    flag--;
                }
                else					//最后一步的情况
                {
                    flag++;
                }
            }
        }
        if(flag==1)
        {
            printf("yes\n");
        }
        else
        {
            printf("no\n");
        }
        scanf("%d %d",&n,&m);
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值