UVA1658 - Admiral 最小费用最大流+拆点

版权声明:本博客内容基本为原创,如有问题欢迎联系,转载请注明出处 https://blog.csdn.net/qq_41955236/article/details/82459111

题目链接:https://uva.onlinejudge.org/external/16/1658.pdf

题意:

       n个地点m条边,有两个人要从1走到n,但是不能经过相同的地点(除了1和n),每条边都有一个权值,问两个人走到地点n花的总权值最小是多少。

做法:


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=400000;
const int maxm=1000000;
const int inf=0x3f3f3f3f;
int dis[maxn];
int vis[maxn],pre[maxn];
int head[maxn],cnt,viss[maxn],visss[maxm];
int n,m,sp,tp,k,W;
ll ans=0;
struct node{
    int to,cap,cost,next;
}e[maxm];
void add(int from,int to,int cap,int cost){
    e[cnt].to=to; e[cnt].cap=cap;
    e[cnt].cost=cost; e[cnt].next=head[from];
    head[from]=cnt++;

    e[cnt].to=from; e[cnt].cap=0;
    e[cnt].cost=-cost; e[cnt].next=head[to];
    head[to]=cnt++;
}
bool spfa(int s,int t,int &flow,int &cost){
    queue<int> q;
    memset(dis,inf,sizeof(dis));
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    dis[s]=0;  q.push(s);
    vis[s]=1;
    int d=inf;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(e[i].cap>0&&dis[v]>dis[u]+e[i].cost){
                dis[v]=dis[u]+e[i].cost;
                pre[v]=i;
                if(!vis[v]){
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    if(dis[t]==inf){
        return false;
    }
    for(int i=pre[t];~i;i=pre[e[i^1].to]){
        d=min(d,e[i].cap);
    }
    for(int i=pre[t];~i;i=pre[e[i^1].to]){
        e[i].cap-=d;
        e[i^1].cap+=d;
        cost+=e[i].cost*d;
    }
    flow+=d;
    return true;
}
int mcmf(int s,int t){
    int flow=0,cost=0;
    while(spfa(s,t,flow,cost)){
        //cout<<flow<<" "<<cost<<endl;
    }
    return cost;
}
int gainp(int m,int n){
    return (m-1)*2+n;
}
int main(){

    while(~scanf("%d%d",&n,&m)){
        memset(head,-1,sizeof(head));
        cnt=0;
        sp=2*n+1;tp=2*n+2;
        add(sp,gainp(1,0),2,0);
        add(gainp(n,1),tp,2,0);
        for(int i=0,x,y,z;i<m;i++){
            scanf("%d%d%d",&x,&y,&z);
            x=gainp(x,1);
            y=gainp(y,0);
            add(x,y,1,z);
        }
        for(int i=1;i<=n;i++){
            int adds=1;
            if(i==1||i==n) adds++;
            add(gainp(i,0),gainp(i,1),adds,0);
        }
        cout<<mcmf(sp,tp)<<endl;
    }


    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41955236/article/details/82459111
今日推荐