题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4183
题意:给你n个点,每个点有一个频率,原点坐标和半径,i到j可达当且仅当i的频率小于j的频率并且两个圆相交,问你从最小的频率到最大的频率,再从最大的频率到最小的频率的方案是否成立(每条边只能使用一次)。
思路:起点-终点,终点-起点其实就是起点-终点是否有两条以上不同的路径,因为每条边只能使用一次,所以权值为1,然后暴力建图跑下最大流模板就可以了。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
using namespace std;
#define N 310
#define M 90010
#define inf 1000000007
typedef struct
{
int v,w,next;
}Node;
Node e[M];
typedef struct
{
int x,y,r;
double f;
}node;
node s[N];
int head[N],vis[N],d[N];
int n,tot;
int cmp(node u,node v)
{
return u.f<v.f;
}
void add(int x,int y,int z)
{
e[tot].v=y;
e[tot].w=z;
e[tot].next=head[x];
head[x]=tot++;
}
int check(int a,int b)
{
double t,ans;
t=(s[a].x-s[b].x)*(s[a].x-s[b].x)+(s[a].y-s[b].y)*(s[a].y-s[b].y);
ans=sqrt(t)-s[a].r-s[b].r;
if(ans>0)
return 0;
return 1;
}
int bfs(int x,int y){
int i,j,k,t;
memset(d,-1,sizeof(d));
queue<int> q;
q.push(x);
d[x]=0;
while(!q.empty()){
t=q.front();
q.pop();
for(i=head[t];i!=-1;i=e[i].next){
j=e[i].v;
k=e[i].w;
if(k&&d[j]==-1){
d[j]=d[t]+1;
if(j==y)
return 1;
q.push(j);
}
}
}
return 0;
}
int dfs(int x,int y,int z){
if(x==y)
return z;
int i,j,k,ans=0;
for(i=vis[x];i!=-1;i=e[i].next){
j=e[i].v;
k=e[i].w;
if(d[j]==d[x]+1){
k=dfs(j,y,min(z-ans,k));
e[i].w-=k;
e[i^1].w+=k;
ans+=k;
if(e[i].w)
vis[x]=i;
if(ans==z)
return ans;
}
}
if(ans==0)
d[x]=-1;
return ans;
}
int dinic(int x,int y){
int ans=0;
while(bfs(x,y)){
memcpy(vis,head,sizeof(head));
ans=ans+dfs(x,y,inf);
}
return ans;
}
int main()
{
int i,j,k,t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
tot=0;
memset(head,-1,sizeof(head));
for(i=0;i<n;i++)
scanf("%lf%d%d%d",&s[i].f,&s[i].x,&s[i].y,&s[i].r);
sort(s,s+n,cmp);
for(i=0;i<n;i++)
for(j=i+1;j<n;j++)
if(check(i,j))
{
add(i,j,1);
add(j,i,0);
}
if(dinic(0,n-1)>=2)
printf("Game is VALID\n");
else
printf("Game is NOT VALID\n");
}
return 0;
}