[SDOI2009] 晨跑 题解

每个点拆成入点和出点。

发现每个点、每条边都只能经过一次,所以所有边的容量都是 \(1\)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=405,M=1e5+5;
int n,m,s,t,k=1,h[N],vis[N];
int to[M],nxt[M],w[M],f[M];
int lst[N],flw[N],dis[N];
void add(int x,int y,int z,int a){
    w[++k]=z;f[k]=a;to[k]=y;
    nxt[k]=h[x];h[x]=k;
    f[++k]=-a;to[k]=x;
    nxt[k]=h[y];h[y]=k;
}queue<int>q;
int spfa(){
    while(q.size()) q.pop();
    memset(lst,-1,sizeof(lst));
    memset(vis,0,sizeof(vis));
    memset(dis,127,sizeof(dis));
    flw[s]=1e9;dis[s]=0;q.push(s);
    while(q.size()){
        int x=q.front();
        q.pop();vis[x]=0;
        for(int i=h[x];i;i=nxt[i]){
            int y=to[i],vl=w[i];
            if(vl&&dis[y]>dis[x]+f[i]){
                lst[y]=i;
                flw[y]=min(flw[x],vl);
                dis[y]=dis[x]+f[i];
                if(!vis[y])
                    q.push(y),vis[y]=1;
            }
        }
    }return lst[t]!=-1;
}int mxflw,mncst;
void MCMF(){
    while(spfa()){
        mxflw+=flw[t];
        mncst+=dis[t]*flw[t];
        for(int i=t;i!=s;i=to[lst[i]^1])
            w[lst[i]]-=flw[t],w[lst[i]^1]+=flw[t];
    }
}signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;s=n+1;t=n;
    for(int i=2;i<n;i++)
        add(i,i+n,1,0);
    for(int i=1;i<=m;i++){
        int u,v,y;
        cin>>u>>v>>y;
        add(u+n,v,1,y);
    }MCMF();cout<<mxflw<<" "<<mncst;
    return 0;
}//spfa:它没有死透
posted @ 2024-05-19 11:00  长安一片月_22  阅读(4)  评论(0编辑  收藏  举报