紫书上的一道题,做法见紫书P378,这篇博客用的第二种方法,关于正确性的证明,画图可以发现如果一个环是负环,跑最小费用流跑出的是环上的所有正边,再减去负边和即为跑一遍的负权,如果是正环,最小费用流即为负权和的相反数,再加上负权和即为0,即没有计入答案。可能这种方法在处理负权时有一定的普遍性,还是要多做题多体会啊。。。。
PS:今天费用流又写错了,写的是dinic中dfs的那种,保留了那部分代码以便日后修改,,还是记录最短路径稳啊。
#include<iostream> #include<cstring> #include<cmath> #include<cstdio> #include<algorithm> #include<vector> using namespace std; const int maxn=100010,inf=1e9; struct node{ double x,y; }a[maxn]; double calc(node a,node b){ return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } struct edg{ int nxt,to,f; double c; }e[maxn]; int pe[maxn],pv[maxn],du[maxn],res,t=1,n,m,last[maxn],S,T,vis[maxn],q[maxn],head,tail; double dis[maxn],Min; void add(int x,int y,int z,double zz){ ++t;e[t].nxt=last[x];last[x]=t;e[t].to=y;e[t].f=z;e[t].c=zz; ++t;e[t].nxt=last[y];last[y]=t;e[t].to=x;e[t].f=0;e[t].c=-zz; } int dfs(int x,int h){ if(x==T){Min+=double(h)*dis[T];return h;} int tmp=0,cp; for(int i=last[x];i;i=e[i].nxt){ int v=e[i].to; if(e[i].f&&dis[v]==dis[x]+e[i].c){ cp=dfs(v,min(h-tmp,e[i].f)); e[i].f-=cp;e[i^1].f+=cp;tmp+=cp; if(h==tmp){return h;} } } return tmp; } void solve(){ while(1){ for(int i=0;i<=n+5;++i)dis[i]=inf; memset(vis,0,sizeof(vis));head=tail=0; q[++tail]=S;dis[S]=0;vis[S]=1; while(head!=tail){ head=(head+1)%maxn; int u=q[head]; for(int i=last[u];i;i=e[i].nxt){ int v=e[i].to; if(e[i].f&&dis[v]>dis[u]+e[i].c){ dis[v]=dis[u]+e[i].c; pe[v]=i;pv[v]=u; if(!vis[v]){ vis[v]=1;tail=(tail+1)%maxn;q[tail]=v; } } } vis[u]=0; } //cout<<dis[T]<<endl; //system("pause"); if(dis[T]==inf)break; int tmp=inf; for(int u=T;u!=S;u=pv[u])tmp=min(tmp,e[pe[u]].f); for(int u=T;u!=S;u=pv[u]){ e[pe[u]].f-=tmp; e[pe[u]^1].f+=tmp; } Min+=tmp*dis[T]; //res+=dfs(S,inf); } } double X,Y; vector<int>bel[maxn]; int cc,cas; int main(){ while(scanf("%d",&n)!=EOF){ if(!n)break; scanf("%lf%lf",&X,&Y); ++cas; double sum=0; t=1;memset(last,0,sizeof(last)); memset(du,0,sizeof(du));res=0;Min=0; for(int i=1;i<=n;++i)bel[i].clear(); for(int i=1;i<=n;++i){ scanf("%lf%lf",&a[i].x,&a[i].y); while(scanf("%d",&cc)!=EOF){ if(!cc)break; bel[i].push_back(cc); } } for(int i=1;i<=n;++i){ int len=bel[i].size(); for(int j=0;j<len;++j){ double vv=Y-calc(a[i],a[bel[i][j]])*X; if(vv<0){ sum+=vv; du[bel[i][j]]++;du[i]--; add(bel[i][j],i,1,-vv); } else{add(i,bel[i][j],1,vv);} } } S=n+1,T=n+2; for(int i=1;i<=n;++i){ if(!du[i])continue; if(du[i]>0)add(S,i,du[i],0); else{add(i,T,-du[i],0);} } solve(); printf("Case %d: %.2lf\n",cas,fabs(sum+Min)); } //system("pause"); return 0; } /* 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 */