[2018.04.23 T3] 最大值

本文介绍了一种利用网络流算法解决发电站最大发电量问题的方法。通过建立最小割模型,处理发电站之间的限制条件,实现最大发电量的计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

暂无链接

最大值

【题目描述】

Shy 有 n 个发电站。每个发电站有一个 level(可正可负的整数),i 号发电站的 level要在 l[i],r[i]之间(包含),Level x 会带来 fi(x)的发电量。

Shy 还有 m 个限制。限制是这样的形式,x[u]≤x[v]+d,表示 u 的 level 小于等于 v 的level 加 d(d 是整数)。

请问最大发电量是多少。

【输入】

第一行两个整数 n,m 表示发电站的数目和限制的数目;

接下来 n 行,每行三个整数 ai,bi,ci 表示 fi,fi(x)=ai*x*x+bi*x+ci;

接下来 n 行每行两个整数 l[i],r[i];

接下来 m 行,每行三个整数 u,v,d,表示 x[u]≤x[v]+d。

【输出】

一个正整数表示答案。

【输入样例】

5 8
1 -8 20
2 -4 0
-1 10 -10
0 1 0
0 -1 1
1 9
1 4
0 10
3 11
7 9
2 1 3
1 2 3
2 3 3
3 2 3
3 4 3
4 3 3
4 5 3
5 4 3

【输出样例】

46

【提示】
【数据规模】

对于 30%的数据,1≤n≤3;

对于 100%的数据,1≤n≤50,0≤m≤100,|ai|≤10,|bi|≤1000,|ci|≤1000, -100≤|li|≤|ri|≤100,1≤u,v≤n,u≠v,|di|≤200。

题解

算是借这道题体会到了网络流的神奇之处,我以前打的都是板子题。。。

这道题可以使用最小割模型,我们将所有发电站的取值范围串起来,边权为ax2+bx+cax2+bx+c记作F(x)F(x),割掉一条边就相当于选取了这个值,以样例中的前两条边为例,连边如下:

那么最主要的问题在于如何处理限制,对于一个x[a]x[b]+cx[a]≤x[b]+c,我们需要使割掉了aa的某个值过后必须割掉比它大c的边,且只有仅割掉那条边后为最小割。那么我们可以建图如下:

这个图是如何完成上述功能的呢?

例如,对于限制x[1]x[2]+3x[1]≤x[2]+3,当我们选择割掉1号发电站F(6)F(6)的边时,我们不能选择割掉2号发电站F(2)F(2)及以下的边,因为这样仍存在通路,迫使我们割掉其他的边:

在上图中,割掉F(1)F(2)F(1),F(2)就是无效的,必须割掉其他的边,而我们求的又是最小割所以我们根本不会割掉F(1)F(2)F(1),F(2),中间的边权值又是INFINF根本割不掉,所以最终我们会去割F(3)F(3)F(4)F(4),这样,我们就成功完成了上述限制。

这个图里面还会有负权的情况,我们只需要在连边时给边权加上一个极大值,因为我们知道我们会割掉nn条边,我们只需要在输出答案时减回来就行(具体见代码)。

建完图以后连一个超级源点、汇点,跑最小割(最大流)即可AC

另外,这道题强制加当前弧优化,不然只有9090分。

代码
#include<bits/stdc++.h>
#define F(i,x) f[i].a*x*x+f[i].b*x+f[i].c
#define R register int
#define I inline
using namespace std;
const int M=1e5+5,N=105,P=19260817,inf=0x3f3f3f3f;
struct edge{int to,fl;};
struct sd{int a,b,c;};
sd f[N];
edge ed[M];
vector<int>mmp[M];
queue<int>dui;
int n,m,id,le[N],ri[N],lb[M],rb[M],lay[M],itr[M],r,fu;
char c;
I int read()
{
    r=0,fu=1;c=getchar();
    while(!isdigit(c)){if(c=='-')fu=-1;c=getchar();}
    while(isdigit(c))r=(r<<1)+(r<<3)+c-'0',c=getchar();
    return r*fu;
}
I void add(int f,int t,int val)
{
    mmp[f].push_back(id);
    ed[id++]=(edge){t,val==inf?inf:P-val};
    mmp[t].push_back(id);
    ed[id++]=(edge){f,0};
}
I bool bfs(int s,int e)
{
    memset(itr,0,sizeof(itr));
    memset(lay,0,sizeof(lay));
    lay[s]=1;dui.push(s);
    R i,f,fl,to,hh;
    while(!dui.empty())
    {
        f=dui.front();dui.pop();
        for(i=mmp[f].size()-1;i>=0;--i)
        {
            hh=mmp[f][i];
            fl=ed[hh].fl;to=ed[hh].to;
            if(lay[to]||!fl)continue;
            lay[to]=lay[f]+1;
            dui.push(to);
        }
    }
    return lay[e];
}
int dfs(int s,int e,int minn)
{
    if(s==e||!minn)return minn;
    int ans=0,tmp,to,fl,hh,siz=mmp[s].size()-1;
    for(int i=itr[s];i<=siz;++i)
    {
        hh=mmp[s][i];
        fl=ed[hh].fl;to=ed[hh].to;
        if(lay[to]!=lay[s]+1||!fl)continue;
        tmp=dfs(to,e,min(fl,minn-ans));
        if(!tmp)continue;
        ed[hh].fl-=tmp;
        ed[hh^1].fl+=tmp;
        ans+=tmp;itr[s]=i;
        if(minn==tmp)break;
    }
    return ans;
}
void in()
{
    R i,j,a,b,c;
    n=read();m=read();
    for(i=1;i<=n;++i)
    f[i].a=read(),f[i].b=read(),f[i].c=read();c=0;
    for(i=1;i<=n;++i)
    {
        le[i]=++c;
        lb[i]=read();rb[i]=read();
        for(j=lb[i];j<=rb[i];++j)
        add(c,c+1,F(i,j)),c++;
        ri[i]=c;
    }
    int x,y,f,t;
    for(i=1;i<=m;++i)
    {
        a=read();b=read();c=read();
        x=lb[a];
        for(j=le[a];j<=ri[a];++j,++x)
        {
            t=x-c;
            if(lb[b]<=t&&t<=rb[b]+1)
            add(j,le[b]+t-lb[b],inf);
        }
    }
    for(i=1;i<=n;++i)
    add(0,le[i],inf),add(ri[i],1e5,inf);
}
void ac()
{
    int ans=0;
    while(bfs(0,1e5))
    ans+=dfs(0,1e5,inf);
    printf("%d",n*P-ans);
}
int main()
{
    in();ac();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShadyPi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值