紫书上的一道题,做法见紫书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
*/

 

posted on 2018-01-17 21:40  湮灭之瞳  阅读(214)  评论(0编辑  收藏  举报