POJ2706Connect(AC)

Connect
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 1390 Accepted: 472

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
 
#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

#define MAXN 25
#define MAXM 255
int N = 0;
int M = 0;

//AC了,但是最关键的线段相交是我看网上的,这个要再看下

int postion[8][2] = { { 2, 1 }, { 1, 2 }, { -1, 2 }, { -2, 1 }, { -2, -1 }, { -1, -2 }, { 1, -2 }, { 2, -1 } };
//思路
//1:首先要连线 然后是找到最后一个点后是否有符合条件的,如果有,还要剔除掉最后一个点,看是否有符合条件的
//对于怎么连线,自己没什么思路

typedef struct peg
{
	int color;
	int x;
	int y;
	int connect[8];//和这个相连的点, 比如当前是点1,然后connect记的5 6 8,说明1->5 1->6 1->8
	int conx[8];
	int cony[8];
	int num; //记这个点和多少点相连
}pegs;

int marix[MAXN][MAXN]; //记棋子的编号
pegs qizi[MAXN*MAXN];
int link[MAXM][MAXM];//记哪些棋子相连,按编号连接
int lastx = 0;
int lasty = 0;

typedef struct Dians
{
	int x;
	int y;
}Dian;

typedef struct Lines
{
	Dian a;
	Dian b;
}Line;

void init()
{
	int i = 0;
	int j = 0;
	int k = 0;
	int m = 0;
	for (i = 0; i < MAXN;i++)
	{
		for (j = 0; j < MAXN; j++)
		{
			marix[i][j] = 0;
			qizi[k].color = 0;
			qizi[k].x = 0;
			qizi[k].y = 0;
			qizi[k].num = 0;
			for (m = 0; m < 8;m++)
			{
				qizi[k].connect[m] = 0;
				qizi[k].conx[m]    = 0;
				qizi[k].cony[m]    = 0;
			}
			k++;
		}
	}

	for (i = 0; i < MAXM; i++)
	{
		for (j = 0; j < MAXM; j++)
		{
			link[i][j] = 0;
		}
	}
	return;
}


int Min(int a, int b)
{
	return a>b ? b : a;
}
int Max(int a, int b)
{
	return a>b ? a : b;
}

int chaji(Dian p1, Dian p2, Dian p0)
{
	return (p1.x - p0.x)*(p2.y - p0.y) - (p1.y - p0.y)*(p2.x - p0.x);
}

int across(Line m, Line n)
{
	if (Min(m.a.x, m.b.x) <= Max(n.a.x, n.b.x) &&
		Min(n.a.x, n.b.x) <= Max(m.a.x, m.b.x) &&
		Min(m.a.y, m.b.y) <= Max(n.a.y, n.b.y) &&
		Min(n.a.y, n.b.y) <= Max(m.a.y, m.b.y) &&
		chaji(m.a, n.b, n.a)*chaji(m.b, n.b, n.a)<0 &&
		chaji(n.a, m.b, m.a)*chaji(n.b, m.b, m.a)<0)
		return 1;
	else    return 0;
}

int check(int index, int x2, int y2)
{
	int i = 0;
	int j = 0;
	int startx1 = qizi[index].x;
	int starty1 = qizi[index].y;
	int startx2 = x2;
	int starty2 = y2;
	int endx1 = 0;
	int endy1 = 0;
	int endx2 = 0;
	int endy2 = 0;

	Line m;
	Line n;
	m.a.x = startx1;
	m.a.y = starty1;
	m.b.x = startx2;
	m.b.y = starty2;

	for (i = 0; i < index;i++)
	{
		for (j = 0; j < qizi[i].num;j++) //依次看已有的线段和现在的线段是否相交
		{
			endx1 = qizi[i].x;
			endy1 = qizi[i].y;
			endx2 = qizi[i].conx[j];
			endy2 = qizi[i].cony[j];

			n.a.x = endx1;
			n.a.y = endy1;
			n.b.x = endx2;
			n.b.y = endy2;

			//开始判断
			if (1 == across(m, n))
			{
				return 0;
			}
		}
	}
	return  1;
}

void line(int index,  int clor)
{
	int i = 0;
	int x1 = 0;
	int y1 = 0;
	//要找8个方向有没有同颜色的棋子,然后有没有线段存在
	for (i = 0; i < 8;i++)
	{
		x1 = qizi[index].x + postion[i][0];
		y1 = qizi[index].y + postion[i][1];
		if (x1<0 || x1 > N || y1<0 || y1> N) continue;
		if (0 == marix[x1][y1]) continue; //没有棋子
		if (clor != qizi[marix[x1][y1]].color) continue; //颜色不一样
		if (1 == link[index][marix[x1][y1]]) continue; //已经相连
		//下面就要判断线段是否相交
		//这个是有公式的
		if (0 == check(index,x1,y1))
		{
			//有线段相交,看下一个点
			continue;
		}
		qizi[index].connect[qizi[index].num] = marix[x1][y1];
		qizi[index].conx[qizi[index].num]    = x1;
		qizi[index].cony[qizi[index].num]    = y1;
		qizi[index].num += 1;

		qizi[marix[x1][y1]].connect[qizi[marix[x1][y1]].num] = marix[qizi[index].x][qizi[index].y];
		qizi[marix[x1][y1]].conx[qizi[marix[x1][y1]].num]    = qizi[index].x;
		qizi[marix[x1][y1]].cony[qizi[marix[x1][y1]].num]    = qizi[index].y;
		qizi[marix[x1][y1]].num += 1;


		link[marix[qizi[index].x][qizi[index].y]][marix[x1][y1]] = 1;
		link[marix[x1][y1]][marix[qizi[index].x][qizi[index].y]] = 1;
	}
	return;
}

int BFS(int last)
{
	int head = 0;
	int end  = 0;
	int index = 0;
	int i = 0;
	int j = 0;
	int p = 0;
	int step[MAXM]  = { 0 };
	int visit[MAXM] = { 0 };
	
	if (1 != last)
	{
		index = M;
	}

	//起点是(0,*)
	for (i = 0; i <= N;i++)
	{
		p = marix[0][i];
		if (0 == p) continue;
		if (index == p) continue;
		if (1 != qizi[p].color) continue; //如果不是黑棋子
		step[end] = p;
		visit[p] = 1;
		end += 1;
		while (head < end)
		{
			if (N == qizi[step[head]].x)
			{
				return 1; //找到一条线
			}

			for (j = 0; j < qizi[step[head]].num;j++)
			{
				if (visit[qizi[step[head]].connect[j]]) continue;
				if (index == qizi[step[head]].connect[j]) continue; //如果这次要剔除掉最后一个点
				step[end] = qizi[step[head]].connect[j];
				visit[qizi[step[head]].connect[j]] = 1;
				end += 1;
			}
			head += 1;
		}
	}	


	return 0;
}

//最后一步连成一条线才算赢
int main()
{
	int i = 0;
	int x = 0;
	int y = 0;
	freopen("input.txt","r",stdin);
	while (scanf("%d %d",&N,&M))
	{
		lastx = 0;
		lasty = 0;
		if ((0 == N) && (0 == M))
			break;
		init();
		for (i = 1; i <= M; i++)
		{
			scanf("%d %d",&x,&y);
			marix[x][y] = i; //给点编号
			qizi[i].x   = x;
			qizi[i].y   = y;
			if (0 == (i%2))
			{
				qizi[i].color = 0;//白棋
			}
			else
			{
				qizi[i].color = 1;//黑棋
			}

			if (i == M)
			{
				lastx = x;
				lasty = y;
			}

			//同颜色的线段也不能相交
			line(i,qizi[i].color);//开始连接图形
		}

		//开始测最后一个黑色棋子是否能连成一条线
		if (1 == BFS(1))
		{
			//没有最后一个点看是否能连成一条线
			if (0 == BFS(0))
			{
				printf("yes\n");
			}
			else
			{
				printf("no\n");
			}
		}
		else
		{
			printf("no\n");
		}
			
		
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值