图论(网络流):UVa 1659 - Help Little Laura
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}](https://uva.onlinejudge.org/external/16/p4030.png)
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 (1n
100, 1
x, y
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
x, y
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\n",++cas,eps-ans-mcmf.MCMF(0,n+1)); 96 } 97 return 0; 98 }
具体就如代码,网络流还是一般的网络流,就是建边很神。
最后的eps是为了防止输出-0.00的情况。