BZOJ 1061 志愿者招募
http://www.lydsy.com/JudgeOnline/problem.php?id=1061
思路:可以用不等式的改装变成费用流.
将不等式列出,如果有负的常数,那么就从等式连向T,如果是正的就从S连向等式,流量为常数,费用为0。
如果是变量,那么找出都有这个变量的两个等式,从负的连向正的流量为inf的边,如果有费用,那就再加上费用。
1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstring> 5 #include<iostream> 6 #define inf 0x7fffffff 7 int tot,go[200005],next[200005],first[200005],flow[200005],cost[200005]; 8 int op[200005],a[200005]; 9 int c[200005],vis[200005],dis[200005]; 10 int S,T,n,m,edge[200005],from[200005],ans; 11 int read(){ 12 int t=0,f=1;char ch=getchar(); 13 while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();} 14 while ('0'<=ch&&ch<='9') {t=t*10+ch-'0';ch=getchar();} 15 return t*f; 16 } 17 void insert(int x,int y,int z,int l){ 18 tot++; 19 go[tot]=y; 20 next[tot]=first[x]; 21 first[x]=tot; 22 flow[tot]=z; 23 cost[tot]=l; 24 } 25 void add(int x,int y,int z,int l){ 26 insert(x,y,z,l);op[tot]=tot+1; 27 insert(y,x,0,-l);op[tot]=tot-1; 28 } 29 bool spfa(){ 30 for (int i=S;i<=T;i++) vis[i]=0,dis[i]=0x7fffffff; 31 int h=1,t=1;vis[S]=1;dis[S]=0; 32 while (h<=t){ 33 int now=c[h++]; 34 for (int i=first[now];i;i=next[i]){ 35 int pur=go[i]; 36 if (flow[i]&&dis[pur]>dis[now]+cost[i]){ 37 edge[pur]=i; 38 from[pur]=now; 39 dis[pur]=dis[now]+cost[i]; 40 if (vis[pur]) continue; 41 vis[pur]=1; 42 c[++t]=pur; 43 } 44 } 45 vis[now]=0; 46 } 47 return dis[T]!=0x7fffffff; 48 } 49 void updata(){ 50 int mn=0x7fffffff; 51 for (int i=T;i!=S;i=from[i]){ 52 mn=std::min(mn,flow[edge[i]]); 53 } 54 for (int i=T;i!=S;i=from[i]){ 55 ans+=mn*cost[edge[i]]; 56 flow[edge[i]]-=mn; 57 flow[op[edge[i]]]+=mn; 58 } 59 } 60 int main(){ 61 n=read();m=read(); 62 S=0;T=n+2; 63 for (int i=1;i<=n;i++) a[i]=read(); 64 for (int i=1;i<=m;i++){ 65 int u=read(),v=read(),c=read(); 66 add(u,v+1,inf,c); 67 } 68 for (int i=1;i<=n+1;i++){ 69 int tmp=a[i]-a[i-1]; 70 if (tmp>=0) add(S,i,tmp,0); 71 else add(i,T,-tmp,0); 72 if (i>1) add(i,i-1,inf,0); 73 } 74 while (spfa()) updata(); 75 printf("%d\n",ans); 76 }