题意:在n*n的棋盘上有依次放上m个棋子。黑子先手。判断最后一个黑子所连成的线段能否贯穿其区域。
若两颗子中间已有直线存在(端点除外),则此两子不能连。且在最后一个黑子之前,不存在黑子连线贯穿整个区域的情况。
判断两线段相交:
因为此题不存在水平线段或者数值线段,所以可以丧心病狂的使用斜率。
设t1,t2为等待被连线的两个点,该线段所在直线斜率为k1,截距为b;
设t3,t4为有可能阻断t1,t2连线的两个点,其所在的斜率亦为k1的直线的截距为b2.b3;
若b,b2,b3满足 (b2 < b < b3) || (b2 > b > b3) 则说明t3,t4所在直线与t1,t2所在直线相交。
然此题是线段,所以还需加限制条件。
如下图:
只需在符合两直线相交的情况下判断两点均在黑线所围成的区域能即可。
剩下的就是简单的BFS了,不再赘述。
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
#include <algorithm>
using namespace std;
struct C
{
int x,y;
C *next;
}*head[25][25];
struct P
{
int x,y;
};
C *creat()
{
C *p = (C *)malloc(sizeof(C));
p->next = NULL;
return p;
}
int mc[25][25];
int jx[] = {-2,-2,-1, 1, 2, 2, 1,-1};//八个方向
int jy[] = {-1, 1, 2, 2, 1,-1,-2,-2};
bool checkC(int x1,int y1,int x2,int y2)//检查与(x1,y1)相连的点中有木有(x2,y2);
{
for(C *p = head[x1][y1]->next;p != NULL; p = p->next)
{
if(p->x == x2 && p->y == y2)
return true;
}
return false;
}
bool judgeinc(int minx,int maxx,int miny,int maxy,int x,int y,int n)//检查(x,y)是否在黑线所围成的区域内
{
int minx1, maxx1, miny1, maxy1;
minx1 = minx-1 >= 0 ? minx-1 : 0;
maxx1 = maxx+1 <= n ? maxx+1 : n;
miny1 = miny-1 >= 0 ? miny-1 : 0;
maxy1 = maxy+1 <= n ? maxy+1 : n;
int i,j;
for(i = minx1;i <= maxx1; ++i)
{
for(j = miny;j <= maxy; ++j)
{
if(i == x && j == y)
return true;
}
}
for(i = minx;i <= maxx; ++i)
{
for(j = miny1;j <= maxy1; ++j)
{
if(i == x && j == y)
return true;
}
}
return false;
}
bool judgeC(P t1,P t2,int n)//判断两点之间是否有线段阻隔
{
int minx,miny,maxx,maxy;
P temp;
minx = (t1.x < t2.x ? t1.x : t2.x);
maxx = (t1.x > t2.x ? t1.x : t2.x);
miny = (t1.y < t2.y ? t1.y : t2.y);
maxy = (t1.y > t2.y ? t1.y : t2.y);
double k,b,b1,b2;
int i,j,u;
k = (t2.y-t1.y)*1.0/(t2.x-t1.x);
b = t2.y*1.0 - k*t2.x;
//实际上只需要检查与t1,t2在同一 ‘日’ 字内的其余四个点
for(i = minx;i <= maxx; ++i)
{
for(j = miny;j <= maxy; ++j)
{
if( !( (i == t1.x && j == t1.y) || (i == t2.x && j == t2.y) ) )
{
b1 = j*1.0 - k*i;
for(u = 0;u < 8;++u)
{
temp.x = i+jx[u];
temp.y = j+jy[u];
if(0 <= temp.x && temp.y <= n && 0 <= temp.y && temp.y <= n)
{
b2 = temp.y*1.0 - k*temp.x;
if( ( (b1 > b && b > b2) || (b1 < b && b < b2) ) && judgeinc(minx,maxx,miny,maxy,temp.x,temp.y,n) && checkC(i,j,temp.x,temp.y) )
return false;
}
}
}
}
}
return true;
}
void link(P t1,P t2)//将t2插入t1的链表内 说明二者可连接
{
C *p = head[t1.x][t1.y];
C *q = creat();
q->x = t2.x;
q->y = t2.y;
q->next = p->next;
p->next = q;
}
void connect(int x,int y,int type,int n)
{
int i;
P t1,t2;
t1.x = x;
t1.y = y;
for(i = 0;i < 8; ++i)
{
t2.x = t1.x+jx[i];
t2.y = t1.y+jy[i];
if(0 <= t2.x && t2.x <= n && 0 <= t2.y && t2.y <= n && mc[t2.x][t2.y] == type && judgeC(t1,t2,n))
{
link(t1,t2);
link(t2,t1);
}
}
}
bool MarkVisit[25][25];
bool judge(int x,int y,int n)//判断最后是否胜利
{
queue<P> q;
memset(MarkVisit,false,sizeof(MarkVisit));
P t1,t2;
t1.x = x;
t1.y = y;
q.push(t1);
MarkVisit[x][y] = true;
bool m1 = false,m2 = false;
C *p;
while(q.empty() == false && (m1 == false || m2 == false))
{
t1 = q.front();
q.pop();
if(t1.y == 0)
m1 = true;
if(t1.y == n)
m2 = true;
for(p = head[t1.x][t1.y]->next; p != NULL ; p = p->next)
{
t2.x = p->x;
t2.y = p->y;
if(MarkVisit[t2.x][t2.y] == false)
{
q.push(t2);
MarkVisit[t2.x][t2.y] = true;
}
}
}
if(m1 && m2)
return true;
return false;
}
int main()
{
int n,m;
int i,j;
int x,y;
int step;
n = 22;
for(i = 0; i <= n; ++i)
{
for(j = 0; j <= n; ++j)
{
head[i][j] = creat();
}
}
while(scanf("%d %d",&n,&m) && (n||m))
{
for(i = 0; i <= n; ++i)
{
for(j = 0; j <= n; ++j)
{
mc[i][j] = 0;
head[i][j]->next = NULL;
}
}
for(step = 1; step <= m; ++step)
{
scanf("%d %d",&y,&x);
if(step&1)
{
mc[x][y] = 1;
connect(x,y,1,n);
}
else
{
mc[x][y] = 2;
connect(x,y,2,n);
}
}
if(judge(x,y,n))
cout<<"yes"<<endl;
else
cout<<"no" <<endl;
}
return 0;
}