bzoj1877: [SDOI2009]晨跑

最小费用最大流。

拆点法建模。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 500 + 10;
const int maxm = 100000 + 10;
const int INF = 0x3f3f3f3f;

int g[maxn],v[maxm],next[maxm],f[maxm],c[maxm],eid;
int id[210][2];
int n,m,vid,S,T;
int dist[maxn],pre[maxn],q[maxm],inque[maxn],l,r;
int res1,res2;

void addedge(int a,int b,int F,int C) {
    v[eid]=b; f[eid]=F; c[eid]=C; next[eid]=g[a]; g[a]=eid++;
    v[eid]=a; f[eid]=0; c[eid]=-C; next[eid]=g[b]; g[b]=eid++;    
}

void build() {
    scanf("%d%d",&n,&m);
    memset(g,-1,sizeof(g));
    for(int i=1;i<=n;i++) {
        id[i][0]=++vid;
        id[i][1]=++vid;    
        addedge(id[i][0],id[i][1],1,0);
    }
    S=id[1][1]; T=id[n][0];
    for(int i=1,a,b,f,c;i<=m;i++) {
        scanf("%d%d%d",&a,&b,&c);
        addedge(id[a][1],id[b][0],1,c);    
    }
}

bool SPFA() {
    memset(dist,0x3f,sizeof(dist));
    l=r=0; dist[S]=0,q[r++]=S;
    while(l<r) {
        int u=q[l++];
        inque[u]=0;
        for(int i=g[u];~i;i=next[i]) 
            if(f[i] && dist[v[i]]>dist[u]+c[i]) {
                dist[v[i]]=dist[u]+c[i];
                pre[v[i]]=i;
                if(!inque[v[i]]) {
                    q[r++]=v[i];
                    inque[v[i]]=1;
                }
            }
    }
    return dist[T]<INF;
}

void augment() {
    int aug=INF;
    for(int i=T;i!=S;i=v[pre[i]^1]) aug=min(aug,f[pre[i]]);
    res1+=aug;
    for(int i=T;i!=S;i=v[pre[i]^1]) {
        f[pre[i]]-=aug; 
        f[pre[i]^1]+=aug;
        res2+=aug*c[pre[i]];
    }
}

void solve() {
    while(SPFA()) augment();    
    printf("%d %d\n",res1,res2);
}

int main() {
    build();
    solve();
    return 0;
}
posted @ 2016-05-16 14:03  invoid  阅读(155)  评论(0编辑  收藏  举报