Codeforces434D 网络流
2024-09-02 00:56:18
思路:
题意:有n<=50个点,每个点有xi有[li, ri]种取值,-100 <= li <= ri <= 100,并且给定m<=100条边,每条边为u,v,d表示xu<=xv+d。
每个点value fi(x) = ai*x^2 + bi*x + ci。现在求一种合法的方案,使得权值和最大。
思路:先不考虑的xu<=xv + d。那么建图:
首先考虑到每个点的权值可能为负,并且求最大与最小割相反,
所以先 取反再+oo(一个很大的数),最后再减掉即可
对于每个点,拆成ri-li+1个点,
对于第k个点,node(k, i)表示第k个点值为i对应的标号
值为i-1跟i连一条边<node(k, i-1), node(k, i), oo - f(k, i)>的边,
S到第一个点连<S, node(k, l[k]), f(k, l[k])>
最后一个点到T连<node(k,r[k]), Inf>
那么很明显n*oo-最小割就是答案。。
但是如果有了限制条件xu<=xv + d,我们怎么把限制条件加到图上呢?
对于一对关系,xu<=xv+d
考虑到点u,如果node(u, i)到node(u,i+1)之间的边在割集里,那么说明xu=i+1
也就是说如果xv<xu-d是非法的,也就是说对于v在xu-d之前出现割是非法的。
那么我们可以连<node(u,i), node(v, i-d), Inf>的边,使得方案合法。。
from http://www.cnblogs.com/yzcstc/p/4062097.html
//By SiriusRen
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 111
#define maxn 11111
#define M 88888
#define inf 0x3f3f3f3f
int n,m,a[N],b[N],c[N],l[N],r[N],id[N][N*2],cnt,maxx=-inf,ed=11100;
int first[maxn],vis[maxn],v[M],w[M],nxt[M],tot,U,V,D,jy,ans;
int func(int x,int y){return a[x]*y*y+b[x]*y+c[x];}
void Add(int x,int y,int z){w[tot]=z,v[tot]=y,nxt[tot]=first[x],first[x]=tot++;}
void add(int x,int y,int z){Add(x,y,z),Add(y,x,0);}
bool tell(){
memset(vis,-1,sizeof(vis)),vis[0]=0;
queue<int>q;q.push(0);
while(!q.empty()){
int t=q.front();q.pop();
for(int i=first[t];~i;i=nxt[i])
if(w[i]&&vis[v[i]]==-1)
vis[v[i]]=vis[t]+1,q.push(v[i]);
}
return vis[ed]!=-1;
}
int zeng(int x,int y){
if(x==ed)return y;
int r=0;
for(int i=first[x];~i&&y>r;i=nxt[i])
if(w[i]&&vis[v[i]]==vis[x]+1){
int t=zeng(v[i],min(w[i],y-r));
w[i]-=t,w[i^1]+=t,r+=t;
}
if(!r)vis[x]=-1;
return r;
}
int main(){
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]);
for(int j=l[i];j<=r[i];j++)
maxx=max(maxx,func(i,j));
}
maxx++;
memset(first,-1,sizeof(first));
for(int i=1;i<=n;i++){
for(int j=l[i];j<=r[i]+1;j++)id[i][j+100]=++cnt;
for(int j=l[i];j<=r[i];j++)add(id[i][j+100],id[i][j+101],maxx-func(i,j));
add(0,id[i][l[i]+100],inf),add(id[i][r[i]+101],ed,inf);
}
for(int i=1;i<=m;i++) {
scanf("%d%d%d",&U,&V,&D);
for(int j=l[U];j<=r[U]+1;j++)
if(j-D>=l[V]&&j-D<=r[V]+1)add(id[U][j+100],id[V][j-D+100],inf);
}
while(tell())while(jy=zeng(0,inf))ans+=jy;
printf("%d\n",maxx*n-ans);
}
最新文章
- Delphi的面向对象编程基础笔记
- PHP For Windows/php-5.6.11-Win32-VC11-x64启动脚本
- C# Control 控件DrapDrop不触发的问题
- 微信扫描二维码安卓弹出默认浏览器(苹果打开App Store)打开下载链接
- 深入MySQL复制(三):半同步复制
- js判断手机邮箱格式(正则)
- Python与矩阵论——特征值与特征向量
- MSMQ消息传递的优先级
- Storm集成Kafka的Trident实现
- VBA 连接文本的自定义函数(可用于数组公式)
- python map对象
- js forEach for区别
- endl的读法
- 简单认识python的数据类型和语法
- Android 第三方应用接入微信平台研究情况分享
- ThinkPHP - 4 - 学习笔记(2015.4.12)
- visualvm监控远程机器上的Java程序
- 在struts2中配置自定义拦截器放行多个方法
- Poco 编译mysql
- 优先队列的使用——Expedition