UVA - 1658 Admiral (最小费用最大流)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a54665sdgf/article/details/80714725

题目大意:给你n个点和m条带权边,让你求出从点1到点n的两条边,使得这两条边没有公共点(除了起点和终点),并且权和最小。

思路:方法很简单,令每条边的容量为1,用最小费用最大流的方法求出流量为2时的最小费用即可。注意由于每个点的容量是没有限制的,只有边的容量有限制,所以不能保证每个点只经过一次。解决方法是把每个点拆成两个点P1和P2,在P1和P2间连一条容量为1、费用为0的边,这样就可以保证走过的点不重复了。在不同的点u、v之间连边的时候,只需要把点P2(u)与P1(v)相连即可。

AC代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
#include<queue>
#define FRER() freopen("i.txt","r",stdin)
using namespace std;
const int M=2000+100,N=30000;
const int INF=0x3f3f3f3f;
int head[M],p[M],dc[M],df[M],vis[M],from[N],to[N],nxt[N],cap[N],cost[N];
int n,m,nEdge,mincost;
void addEdge(int u,int v,int cap_,int cost_)
{
    nxt[nEdge]=head[u],from[nEdge]=u,to[nEdge]=v,cap[nEdge]=cap_,cost[nEdge]=cost_,head[u]=nEdge++;
    nxt[nEdge]=head[v],from[nEdge]=v,to[nEdge]=u,cap[nEdge]=0,cost[nEdge]=-cost_,head[v]=nEdge++;
}
int P1(int u)
{
    return (u-1)*2;
}
int P2(int u)
{
    return (u-1)*2+1;
}
void BellmanFord(int s,int t)
{
    memset(dc,INF,sizeof dc);
    queue<int> q;
    for(int k=0; k<2; ++k)
    {
        memset(dc,INF,sizeof dc);
        memset(df,0,sizeof df);
        memset(vis,0,sizeof vis);
        q.push(s);
        vis[s]=1;
        dc[s]=0,df[s]=1;
        while(!q.empty())
        {
            int u=q.front();
            q.pop(),vis[u]=0;
            for(int e=head[u]; e!=-1; e=nxt[e])
            {
                int v=to[e];
                if(cap[e]&&dc[u]+cost[e]<min(dc[v],dc[t]))
                {
                    dc[v]=dc[u]+cost[e];
                    p[v]=e,df[v]=min(df[u],cap[e]);
                    if(!vis[v])
                        vis[v]=1,q.push(v);
                }
            }
        }
        mincost+=dc[t];
        for(int u=t; u!=s; u=from[p[u]])
            cap[p[u]]-=df[t],cap[p[u]^1]+=df[t];
    }
}
int main()
{
    //FRER();
    while(scanf("%d%d",&n,&m)==2)
    {
        nEdge=mincost=0;
        memset(head,-1,sizeof head);
        int u,v,c;
        while(m--)
        {
            scanf("%d%d%d",&u,&v,&c);
            addEdge(P2(u),P1(v),1,c);
        }
        for(int u=2; u<=n-1; ++u)
            addEdge(P1(u),P2(u),1,0);
        BellmanFord(P2(1),P1(n));
        printf("%d\n",mincost);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/a54665sdgf/article/details/80714725