题意:有很多的被涂上颜色的呈圆形的垫子,一些垫子可以有相同的颜色,但是红色和紫罗兰只有一个,垫子摆放的时候可以相交,初始一个人站在红垫子上,这个人要从红垫子走到紫罗兰垫子,然后再从紫罗兰垫子走到红垫子,问你是否可以在满足以下条件完成上述的动作。
~rule1(red->violet):a垫子和b垫子相交(要有公共面积,点不算)P(a)<P(b);则可以从a走到b;
~rule2(violet->red):a垫子和b垫子相交(要有公共面积,点不算)P(a)>P(b);则可以从a走到b;
思路:
点双连通分量:分量内的任意一个点到其中的其它各点都有两条没有公共点的路径相通。
建图的时候不一定所有满足条件的边都要建,只要建与red_pad和violet_pad有关的边即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<stack>
using namespace std;
const int pad_num=300+5;
const int edge=305*305;
int n;
int red_id,vio_id;
struct node
{
double fre;
int x,y;
int rad;
}pad[pad_num];
struct nodee
{
int v,next;
}e[edge];
int head[pad_num],cnt;
int vis[pad_num];
void Init()
{
memset(head,-1,sizeof(head));
cnt=0;
}
void add(int a,int b)
{
e[cnt].v=b;
e[cnt].next=head[a];
head[a]=cnt++;
}
int Input()
{
int red=0,vio=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lf %d %d %d",&pad[i].fre,&pad[i].x,&pad[i].y,&pad[i].rad);
if(abs(pad[i].fre-400)<1e-8)
{
red_id=i;red=1;
}
if(abs(pad[i].fre-789)<1e-8)
{
vio_id=i;vio=1;
}
}
if(red==0||vio==0) return 0;
return 1;
}
double Dis(int x1,int y1,int x2,int y2)
{
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
void dfs(int i)
{
vis[i]=1;
for(int j=1;j<=n;++j) {
if(i==j) continue;
if(Dis(pad[i].x,pad[i].y,pad[j].x,pad[j].y)>(pad[i].rad+pad[j].rad)) continue;
if(fabs(pad[j].fre-pad[i].fre)<1e-8) continue;
if(pad[j].fre<pad[i].fre) continue;
add(i,j);
add(j,i);
if(!vis[j]) dfs(j);
}
}
void buildmap()
{
memset(vis,0,sizeof vis);
dfs(red_id);
}
struct nnode
{
int f,t;
}ee[pad_num];
int paint[pad_num],dfn[pad_num],low[pad_num],index,col;
stack<nnode>s;
void Init_tarjan()
{
memset(paint,0,sizeof(paint));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
index=col=1;
while(!s.empty()) s.pop();
}
int Min(int a,int b)
{
if(a<b) return a;
return b;
}
void tarjan(int u,int f)
{
dfn[u]=low[u]=index++;
for(int i=head[u];i+1;i=e[i].next)
{
int v=e[i].v;
nnode w;
w.f=u;w.t=v;
if(!dfn[v])
{
s.push(w);
tarjan(v,u);
low[u]=Min(low[u],low[v]);
if(low[v]>=dfn[u])
{
while(1)
{
nnode w=s.top();
s.pop();
paint[w.f]=col;
paint[w.t]=col;
if(w.f==u) break;
}
col++;
}
}
else if(v!=f&&dfn[u]>dfn[v])
{
low[u]=Min(low[u],dfn[v]);
}
}
}
void treatment()
{
Init_tarjan();
for(int i=1;i<=n;i++)
{
if(!dfn[i]) tarjan(i,-1);
}
if(paint[red_id]==paint[vio_id]&&paint[red_id]!=0)
printf("Game is VALID\n");
else printf("Game is NOT VALID\n");
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
Init();
if(!Input())
{
printf("Game is NOT VALID\n");
continue;
}
buildmap();
treatment();
}
return 0;
}