HDU 4183 Pahom on Water

题意:水面上有很多的圆形区域,他们要么存在相交的区域,要么不存在相交的区域,不会存在相切的情况。每个区域都有颜色,并且告诉你每个区域颜色的频率。现在要求你从唯一的一个红色区域(频率最小)走到紫色区域(频率最大)并从紫色区域返回红色区域。并且必须遵循以下三个规则:(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 }
View Code
原文地址:https://www.cnblogs.com/zhexipinnong/p/3389183.html