传送门:bzoj1877
题解
裸的最小费用最大流,拆点强制出入度<=1即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=450,M=2e5+10,inf=0x7f7f7f7f;
int n,m,dis[N],vs[N],tim,S,T,cost,ans;
int head[N],to[M],nxt[M],w[M],c[M],tot=1;
bool inq[N];
inline void lk(int u,int v,int fw,int vv)
{
to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=fw;c[tot]=vv;
to[++tot]=u;nxt[tot]=head[v];head[v]=tot;w[tot]=0;c[tot]=-vv;
}
deque<int>que;
inline bool bfs()
{
int i,j,x;
memset(dis,0x7f,sizeof(int)*(T+3));
dis[T]=0;que.push_back(T);inq[T]=true;
for(;que.size();){
x=que.front();que.pop_front();
for(i=head[x];i;i=nxt[i]){
j=to[i];if((!w[i^1]) || (dis[j]<=dis[x]-c[i])) continue;
dis[j]=dis[x]-c[i];if(inq[j]) continue;
if(que.empty() || dis[j]<=dis[que.front()]) que.push_front(j);
else que.push_back(j);inq[j]=true;
}
inq[x]=false;
}
return (dis[S]<inf);
}
int dfs(int x,int f)
{
vs[x]=tim;
if(x==T) return f;
int i,j,ss=0,res;
for(i=head[x];i;i=nxt[i]){
j=to[i];if(vs[j]==tim || (!w[i]) || dis[j]!=dis[x]-c[i]) continue;
res=dfs(j,min(w[i],f-ss));if(!res) continue;
ss+=res;cost+=c[i]*res;w[i]-=res;w[i^1]+=res;
if(ss==f) return ss;
}
if(!ss) dis[x]=inf;
return ss;
}
int main(){
int i,j,x,y,z;
scanf("%d%d",&n,&m);
S=1;T=(n<<1);
lk(S,1+n,inf,0);lk(n,T,inf,0);
for(i=2;i<n;++i) lk(i,i+n,1,0);
for(i=1;i<=m;++i){
scanf("%d%d%d",&x,&y,&z);
lk(x+n,y,1,z);
}
for(;bfs();)
for(vs[T]=tim;vs[T]==tim;) {
tim++;ans+=dfs(S,inf);
}
printf("%d %d",ans,cost);
return 0;
}