bzoj1061【Noi2008】志愿者招募
题意:http://www.lydsy.com/JudgeOnline/problem.php?id=1061
有n天m种人,每天用a[i]个人,每种人工作时间为[l,r],费用为c[i],求最小费用
sol :orz byvoid https://www.byvoid.com/blog/noi-2008-employee/
一种神奇的线性规划单纯形做法QAQ然而我不会
不过可以转成有上下界的最小费用可行流
将每一天看成一个点,源点为1,汇点为n+1
第i天向第i+1天连一条(i,i+1,a[i],inf,0)的边
对于一种志愿者,从l[i]+1向r[i]连一条(l[i]+1,r[i],0,inf,c[i])的边
跑上下界最小费用可行流,S到T不连边
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int Mx1=20010; const int Mx2=1000010; int S,T,n,m,tot; int ver[Mx2],nxt[Mx2],head[Mx1],a[Mx1],c[Mx1],s[Mx1],e[Mx1],pos[Mx1],nag[Mx1]; long long edge[Mx2],cost[Mx2],dis[Mx1],with[Mx1],minn[Mx1]; bool vis[Mx1]; void add(int u,int v,int dd,int c) { tot++; nxt[tot]=head[u];head[u]=tot;ver[tot]=v;cost[tot]=c;edge[tot]=dd; tot++; nxt[tot]=head[v];head[v]=tot;ver[tot]=u;cost[tot]=-c;edge[tot]=0; } void clear() { memset(vis,0,sizeof(vis)); memset(dis,0x3f,sizeof(dis)); memset(minn,0x3f,sizeof(minn)); memset(with,0,sizeof(with)); } bool Spfa() { clear(); queue <int> q; q.push(S); vis[S]=1,dis[S]=0; while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i;i=nxt[i]) { int v=ver[i]; if(dis[v]>dis[u]+cost[i]&&edge[i]>0) { dis[v]=dis[u]+cost[i]; with[v]=i; minn[v]=min(minn[u],edge[i]); if(!vis[v]) { vis[v]=1; q.push(v); } } } } return dis[T]!=0x3f3f3f3f3f3f3f3fLL; } int f(int x)//反向弧 { if(x%2) return x+1; else return x-1; } int find_way()//寻找增广路 { for(int i=T;i!=S;i=ver[f(with[i])]) { edge[with[i]]-=minn[T]; edge[f(with[i])]+=minn[T]; } return minn[T]*dis[T]; } long long solve() { long long temp,ret=0; while(Spfa()) { temp=find_way(); ret+=temp; } return ret; } int main() { scanf("%d%d",&n,&m);S=n+m+10,T=S+1; for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=m;i++) { scanf("%d%d%d",&s[i],&e[i],&c[i]); add(e[i]+1,s[i],0x7f7f7f7f,c[i]); } for(int i=2;i<=n+1;i++) add(i-1,i,0x7f7f7f7f,0); for(int i=1;i<=n+1;i++) { int temp=a[i]-a[i-1]; if(temp>=0) add(i,T,temp,0); else add(S,i,-temp,0); } for(int i=1;i<=m;i++) add(nag[i],pos[i],0x7f7f7f7f,c[i]); printf("%lld\n",solve()); return 0; }