zoukankan      html  css  js  c++  java
  • 图论(网络流):UVa 1659

    Laura Luo has just invented a game. Given a beautiful pencil sketch with n points, you're to colorize it with water pens by painting circuits. Each time you paint a new circuit, starts with one point, follow some line segments and return to the starting point. Every point can be reached more than once, but every segment can be painted at most once. To make the picture look interesting, different segments must be painted different colors. For each segment, Laura has already decided a direction to paint it. The picture below illustrates a possible way to paint the picture (dashed lines are segments that are not painted).

    epsfbox{p4030.eps}

    After you finish painting, your score is computed as follows: for each unit length you paint, you earn x points, for each color you use, you lost y points (Laura has prepared enough water pens of different colors).

    Write a program to find the maximal score you can get.

    Input 

    The input contains several test cases. The first line of each case contains three positive integers n, x, y (1$ le$n$ le$100, 1$ le$x, y$ le$1000) . The next n lines each describe a point (points are numbered from 1 to n in the order they appear in the input). The first two integers (x, y) specify its coordinates (0$ le$x, y$ le$1000) . The rest integers are the points it connects to, ended by a zero. If point v appears in the list of point u , there is a line segment connecting u and v (then there will not a segment connecting u and v in the reverse direction). Furthermore, Laura will paint it from u to v . There will be no duplicated points and no more than 500 segments. The last test case is followed by a single zero, which should not be processed.

    Output 

    For each test case, print the case number and the maximal score you can get, to two decimal places.

    Sample Input 

    4 5 1 
    0 0 2 3 0 
    1 0 3 4 0 
    1 1 4 0 
    0 1 1 0 
    1 2 1 
    0 0 0 
    10 7 2 
    0 0 2 4 0 
    5 0 3 0 
    5 10 4 10 0 
    2 3 5 0 
    7 5 6 0 
    0 11 1 0 
    8 0 10 5 0 
    18 3 7 0 
    14 5 8 1 0 
    12 9 9 0 
    0
    

    Sample Output 

    Case 1: 16.00

    Case 2: 0.00

    Case 3: 522.18

      

      这道题就是最小费用循环流的模板,先上代码。

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 #include <queue>
     5 #include <cmath>
     6 using namespace std;
     7 const int N=110;
     8 const int M=20010;
     9 const int INF=1061109567;
    10 const double dINF=1e9;
    11 const double eps=1e-6;
    12 int w[N],cnt,fir[N],to[M],nxt[M];
    13 int cap[M],path[N],vis[N];
    14 double val[M],dis[N];
    15 queue<int>q;
    16 struct Net_Flow{
    17     void Init(){memset(fir,0,sizeof(fir));cnt=1;}
    18     
    19     void add(int a,int b,int c,double v){
    20         nxt[++cnt]=fir[a];cap[cnt]=c;
    21         to[cnt]=b;val[cnt]=v;fir[a]=cnt;
    22     }
    23     
    24     void addedge(int a,int b,int c,double v){
    25         add(a,b,c,v);add(b,a,0,-v);
    26     }
    27     
    28     double Spfa(int S,int T){
    29         fill(dis,dis+T+1,dINF);
    30         q.push(S);vis[S]=1;dis[S]=0;
    31         while(!q.empty()){
    32             int x=q.front();q.pop();vis[x]=0;
    33             for(int i=fir[x];i;i=nxt[i])
    34                 if(cap[i]&&dis[to[i]]-dis[x]-val[i]>eps){
    35                     dis[to[i]]=dis[x]+val[i];
    36                     if(!vis[to[i]])q.push(to[i]);
    37                     vis[to[i]]=1;path[to[i]]=i;
    38                 }
    39         }
    40         return dis[T];
    41     }
    42     
    43     int Aug(int S,int T){
    44         int p=T,f=INF;
    45         while(p!=S){
    46             f=min(f,cap[path[p]]);
    47             p=to[path[p]^1];
    48         }p=T;
    49         while(p!=S){
    50             cap[path[p]]-=f;
    51             cap[path[p]^1]+=f;
    52             p=to[path[p]^1];
    53         }
    54         return f;
    55     }
    56     
    57     double MCMF(int S,int T){
    58         double v=0,d;
    59         while((d=Spfa(S,T))!=dINF)
    60             v+=d*Aug(S,T);
    61         return v;
    62     }
    63 }mcmf;
    64 int deg[N];
    65 int a[N],b[N],G[N][N];
    66 int sqr(int x){
    67     return x*x;
    68 }
    69 int main(){
    70     int n,x,y,cas=0;double ans;
    71     while(scanf("%d%d%d",&n,&x,&y)!=EOF){
    72         if(!n)break;
    73         mcmf.Init();ans=0.0;
    74         memset(G,0,sizeof(G));
    75         memset(deg,0,sizeof(deg));
    76         for(int i=1;i<=n;i++){
    77             int t;
    78             scanf("%d%d%d",&a[i],&b[i],&t);
    79             while(t){G[i][t]=1;scanf("%d",&t);}
    80         }
    81         for(int i=1;i<=n;i++)
    82             for(int j=1;j<=n;j++)if(G[i][j]){
    83                 double v=y-x*sqrt(sqr(a[i]-a[j])+sqr(b[i]-b[j]));    
    84                 if(v<0){
    85                     mcmf.addedge(j,i,1,-v);
    86                     ans+=v;deg[j]+=1;deg[i]-=1;
    87                 }
    88                 if(v>0)mcmf.addedge(i,j,1,v);
    89             }
    90                 
    91         for(int i=1;i<=n;i++){
    92             if(deg[i]>0)mcmf.addedge(0,i,deg[i],0);
    93             if(deg[i]<0)mcmf.addedge(i,n+1,-deg[i],0);
    94         }
    95         printf("Case %d: %.2f
    ",++cas,eps-ans-mcmf.MCMF(0,n+1));
    96     }
    97     return 0;
    98 }
      具体就如代码,网络流还是一般的网络流,就是建边很神。
      最后的eps是为了防止输出-0.00的情况。

  • 相关阅读:
    Java Number & Math 类
    excel小技巧-转置(表的横向纵向倒过来)
    excel小技巧-提取填充
    excel小技巧-分列
    Java switch case语句
    if...else
    12.15个人总结
    12.9个人总结
    11.29个人总结
    11.25日个人总结
  • 原文地址:https://www.cnblogs.com/TenderRun/p/5750765.html
Copyright © 2011-2022 走看看