[Codeforces Round #248][Codeforces 434D] Nanami's Power Plant
题意:有n个点,设每个点的权值为xi,要求Li<=xi<=Ri,另有m个约束ui,vi,di表示xui<=xvi+d,求∑f(i,xi) (f(i,xi)=aix2i+bixi+ci)的最大值。(1<=n<=50,0<=m<=100,|ai|<=10,|bi|,|ci|<=1000,|di|<=200,且题目保证有解)
题解:这种约束一般用网络流做,先直接讲一下建图方法。由于网络流求得是最小割,而我们要求最大值,所以可以先取一个足够大的M,使M>=max{f(i,xi)}。
1.将第i个点拆成Li−1...Ri共Ri−Li+2个点,记为node(i,x)。
2.从S向node(i,Li−1)连一条容量无穷大的边。
3.从node(i,Ri)向T连一条容量无穷大的边。
4.从node(i,x)向node(i,x+1连一条容量为M−f(i,x+1)的边,Li−1<=x<Ri。
5.从node(ui,x)向node(vi,x−d)连一条容量为无穷大的边,其中Lui−1<=x<=Rui,Lvi−1<=x−d<=Rvi。
第5次连边可以完成约束条件,这个从该图的最小割模型中很容易看出来。
答案即M∗n−maxflow。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | #include <bits/stdc++.h> using namespace std; const int maxn=10060,maxm=100010,inf=~0U>>2; int head[maxn],nxt[maxm],E[maxm],F[maxm],Ecnt; int ncnt[maxn]; int a[60],b[60],c[60]; int l[60],r[60]; int M; int n,m,S,T; int f( int x, int e) { return a[x]*e*e+b[x]*e+c[x]; } int node( int x, int e) { return ncnt[x]+e-l[x]+2; } void Add_Edge( int x, int y, int flow) { nxt[++Ecnt]=head[x];head[x]=Ecnt;E[Ecnt]=y;F[Ecnt]=0; nxt[++Ecnt]=head[y];head[y]=Ecnt;E[Ecnt]=x;F[Ecnt]=flow; } int h[maxn],cur[maxn],argu; bool BFS() { static int q[maxn]; memset (h,0, sizeof (h)); for ( int i=1;i<=node(n,r[n]);i++) cur[i]=head[i]; int top=0,tail=0; q[0]=S; h[S]=1; while (top<=tail) { int x=q[top++]; for ( int i=head[x];i;i=nxt[i]) if (!h[E[i]] && F[i^1]) h[E[i]]=h[x]+1,q[++tail]=E[i]; } return h[T]>0; } bool DFS( int x, int flow) { if (x==T) {argu=flow; return 1;} for ( int &i=cur[x];i;i=nxt[i]) if (h[E[i]]==h[x]+1 && F[i^1]) if (DFS(E[i],min(flow,F[i^1]))) { F[i]+=argu; F[i^1]-=argu; return true ; } h[x]=0; return false ; } int Dinic() { int res=0; while (BFS()) while (DFS(S,inf)) res+=argu; return res; } int main() { Ecnt=1; S=1;T=2;ncnt[1]=2; scanf ( "%d%d" ,&n,&m); for ( int i=1;i<=n;i++) scanf ( "%d%d%d" ,&a[i],&b[i],&c[i]); for ( int i=1;i<=n;i++) scanf ( "%d%d" ,&l[i],&r[i]),ncnt[i+1]=ncnt[i]+r[i]-l[i]+2; M=500000; for ( int i=1;i<=n;i++) { Add_Edge(S,node(i,l[i]-1),inf); Add_Edge(node(i,r[i]),T,inf); for ( int j=l[i];j<=r[i];j++) Add_Edge(node(i,j-1),node(i,j),M-f(i,j)); } for ( int i=1;i<=m;i++) { int u,v,d; scanf ( "%d%d%d" ,&u,&v,&d); for ( int j=max(l[v]+d-1,l[u]-1);j<=min(r[v]+d,r[u]);j++) Add_Edge(node(u,j),node(v,j-d),inf); } int ans=Dinic(); printf ( "%d\n" ,M*n-ans); return 0; } |