HDU 4744 Starloop System(ZKW费用流)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4744

题意:三维空间n个点,每个点有一个wi值。每对点的距离定义为floor(欧拉距离),每对点之间建一条边的费用为两点间的距离,每对点之间可以建多条边。现要求对每一个点 i ,都在wi 个简单环上(每个点每条边都只经过一次),每条边只能属于一个简单环,简单环的费用为每条边的费用之和,问最小的建环费用。

思路:每个点拆成a、b两个点,从附加源点S到a连一条边,容量为wi,费用为0;从b到附加汇点T连一条边,容量为wi,费用为0。每两个点i, j之间,ai到bj连一条边,bi到aj连一条边,费用均为i, j的距离,容量均为无穷大。若最大流=sum{wi},那么有解,输出最小费用,否则输出-1。

 

struct node

{

    int u,v,next,cost,cap;

};





node edges[N*500];

int head[N],e;





void add(int u,int v,int cap,int cost)

{

    edges[e].u=u;

    edges[e].v=v;

    edges[e].cap=cap;

    edges[e].cost=cost;

    edges[e].next=head[u];

    head[u]=e++;

}





void Add(int u,int v,int cap,int cost)

{

    add(u,v,cap,cost);

    add(v,u,0,-cost);

}





int dis[N],S,T,nodeNum;

int maxFlow,minCost;



void SPFA()

{

    int i;

    for(i=0;i<=nodeNum;i++) dis[i]=INF;

    priority_queue<pair<int,int> > Q;

    dis[S]=0;

    Q.push(MP(0,S));

    int u,v,d;

    while(!Q.empty())

    {

        u=Q.top().second;

        d=-Q.top().first;

        Q.pop();



        if(dis[u]!=d) continue;

        for(i=head[u];i!=-1;i=edges[i].next)

        {

            v=edges[i].v;

            if(edges[i].cap&&dis[v]>d+edges[i].cost)

            {

                dis[v]=d+edges[i].cost;

                Q.push(MP(-dis[v],v));

            }

        }

    }

    for(i=0;i<=nodeNum;i++) dis[i]=dis[T]-dis[i];

}



int h[N];





int DFS(int u,int flow)

{

    if(u==T)

    {

        maxFlow+=flow;

        minCost+=flow*dis[S];

        return flow;

    }

    h[u]=1;

    int now=flow,i,v,temp;

    for(i=head[u];i!=-1;i=edges[i].next)

    {

        v=edges[i].v;

        if(edges[i].cap&&!h[v]&&dis[u]==dis[v]+edges[i].cost)

        {

            temp=DFS(v,min(now,edges[i].cap));

            edges[i].cap-=temp;

            edges[i^1].cap+=temp;

            now-=temp;

            if(!now) break;

        }

    }

    return flow-now;

}



int modifyLabel()

{

    int d=INF,i,j,v;

    for(i=1;i<=nodeNum;i++) if(h[i])

    {

        for(j=head[i];j!=-1;j=edges[j].next)

        {

            v=edges[j].v;

            if(edges[j].cap&&!h[v])

            {

                upMin(d,dis[v]+edges[j].cost-dis[i]);

            }

        }

    }

    if(d==INF) return 0;

    for(i=0;i<=nodeNum;i++) if(h[i]) dis[i]+=d;

    return 1;

}



int MCMF(int s,int t,int n)

{

    S=s; T=t; nodeNum=n;

    SPFA();

    maxFlow=minCost=0;

    int i;

    while(1)

    {

        while(1)

        {

            for(i=0;i<=nodeNum;i++) h[i]=0;

            if(!DFS(s,INF)) break;

        }

        if(!modifyLabel()) break;

    }

    return minCost;

}







struct point

{

    double x,y,z;



    void get()

    {

        cin>>x>>y>>z;

    }

};



point p[N];

int W[N],n,s,t;

int d[N][N];



int dist(point a,point b)

{

    double L=sqr(a.x-b.x)+sqr(a.y-b.y)+sqr(a.z-b.z);

    L=sqrt(L);

    L=floor(L);

    return L;

}



int main()

{

    Rush(n)

    {

        if(!n) break;

        int i,sum=0;

        FOR1(i,n) p[i].get(),RD(W[i]),sum+=W[i];

        int j;

        for(i=1;i<=n;i++) for(j=i+1;j<=n;j++)

        {

            d[i][j]=d[j][i]=dist(p[i],p[j]);

        }

        clr(head,-1); e=0;

        s=0; t=n*2+1;

        FOR1(i,n) Add(s,i,W[i],0),Add(i+n,t,W[i],0);

        FOR1(i,n)  FOR1(j,n) if(i!=j)

        {

            Add(i,n+j,INF,d[i][j]);

        }

        S=0;

        i64 ans=MCMF(s,t,t+1);

        if(maxFlow!=sum) ans=-1;

        PR(ans);

    }

}

  

你可能感兴趣的:(System)