题意:水面上有很多的圆形区域,他们要么存在相交的区域,要么不存在相交的区域,不会存在相切的情况。每个区域都有颜色,并且告诉你每个区域颜色的频率。现在要求你从唯一的一个红色区域(频率最小)走到紫色区域(频率最大)并从紫色区域返回红色区域。并且必须遵循以下三个规则:(1)从红色走到紫色的时候,必须从频率小的区域走向频率大的区域。(2)从紫色走到红色的时候,必须从频率大的区域走向频率小的区域。(3)除了初始的红色区域,你每离开一个区域的时候,那个区域都会消失。问你是否存在一个合法的方式。
这里最关键的问题是要形成回路。
首先,如果红色区域跟紫色区域直接相交,那就直接可以判为存在合法方案了。
如果不想交,首先肯定要拆点,因为每个区域只能经过一次,所以对于点i,对应边(i,i',1)。另外,本题中要求必须先从红色区域经过紫色区域再返回,网络流中很难实现先经过一个T点,再经过另外一个T点,如果把红色区域作为起点,这会很麻烦。所以不如把紫色区域作为源点,对应一条边(S,S',2),对于任意的相邻的两块区域i和j,假定i的频率大于j的频率,那就连一条边(i+n,j,1),然后以红色区域作为汇点,跑一遍最大流,如果maxflow=2,则说明存在合法的方案了。因为把从S(紫色)->T(红色)的两个流中的一个流反向,就可以形成一个从T->S->T的方案了。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define INF 1<<30 6 #define maxn 1010 7 #define maxm 100000 8 using namespace std; 9 10 int v[maxm],next[maxm],w[maxm]; 11 int first[maxn],d[maxn],work[maxn],q[maxn]; 12 int e,S,T; 13 14 void init(){ 15 e = 0; 16 memset(first,-1,sizeof(first)); 17 } 18 19 void add_edge(int a,int b,int c){ 20 //printf("add:%d to %d,cap = %d ",a,b,c); 21 v[e] = b;next[e] = first[a];w[e] = c;first[a] = e++; 22 v[e] = a;next[e] = first[b];w[e] = 0;first[b] = e++; 23 } 24 25 int bfs(){ 26 int rear = 0; 27 memset(d,-1,sizeof(d)); 28 d[S] = 0;q[rear++] = S; 29 for(int i = 0;i < rear;i++){ 30 for(int j = first[q[i]];j != -1;j = next[j]) 31 if(w[j] && d[v[j]] == -1){ 32 d[v[j]] = d[q[i]] + 1; 33 q[rear++] = v[j]; 34 if(v[j] == T) return 1; 35 } 36 } 37 return 0; 38 } 39 40 int dfs(int cur,int a){ 41 if(cur == T) return a; 42 for(int &i = work[cur];i != -1;i = next[i]){ 43 if(w[i] && d[v[i]] == d[cur] + 1) 44 if(int t = dfs(v[i],min(a,w[i]))){ 45 w[i] -= t;w[i^1] += t; 46 return t; 47 } 48 } 49 return 0; 50 } 51 52 int dinic(){ 53 int ans = 0; 54 while(bfs()){ 55 memcpy(work,first,sizeof(first)); 56 while(int t = dfs(S,INF)) ans += t; 57 } 58 return ans; 59 } 60 61 struct Node{ 62 int x,y,r; 63 double fr; 64 }node[310]; 65 66 bool judge(Node a,Node b){ 67 int x1 = a.x,y1 = a.y,r1 = a.r; 68 int x2 = b.x,y2 = b.y,r2 = b.r; 69 if((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2) < (r1+r2)*(r1+r2)) return true; 70 return false; 71 } 72 73 int main() 74 { 75 int kase,n; 76 scanf("%d",&kase); 77 while(kase--){ 78 init(); 79 scanf("%d",&n); 80 for(int i = 0;i < n;i++){ 81 scanf("%lf%d%d%d",&node[i].fr,&node[i].x,&node[i].y,&node[i].r); 82 if(node[i].fr == 400.0) T = i; 83 else if(node[i].fr == 789.0) S = i; 84 else add_edge(i,i+n,1); 85 } 86 if(judge(node[S],node[T])){ 87 printf("Game is VALID "); 88 continue; 89 } 90 add_edge(S,S+n,2); 91 for(int i = 0;i < n;i++){ 92 for(int j = i+1;j < n;j++){ 93 if(judge(node[i],node[j])){ 94 if(node[i].fr < node[j].fr) add_edge(j+n,i,1); 95 else add_edge(i+n,j,1); 96 } 97 } 98 } 99 int ans = dinic(); 100 //printf("ans = %d ",ans); 101 if(ans == 2) printf("Game is VALID "); 102 else printf("Game is NOT VALID "); 103 } 104 return 0; 105 }