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; }