[数学] Topcoder SRM560 Div1 1000. BoundedOptimization

本文介绍了一种解决特定类型的优化问题的方法,通过枚举变量的边界和中间值来寻找最大值。利用数学推导简化问题,并通过编程实现算法,最终找到满足约束条件下的最优解。

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

可以枚举每个元素的值是上界、下界还是中间值,总共有 3n3n 种情况

若存在两个元素 xi,xjxi,xj,它们都取中间值,且xixjxixj 不在式子中,

那么设表达式为 axi+bxj+caxi+bxj+c,可以发现最有情况肯定是 xixixjxj 达到边界值

kk 为取中间值的元素的个数

所以表达式可以写作 ijxixj+aixi 其中 xixi 为取中间值的元素

化一下式子得到

ki=1xi(jixj+2ai)2∑i=1kxi(∑j≠ixj+2ai)2

S=ki=1aiS=∑i=1kai

ki=1xi(Sxi+2ai)2∑i=1kxi(S−xi+2ai)2

也就是说 xixiS+2ai2S+2ai2 最优

但是这样 xi∑xi 可能大于 SS,所以要减小 xi,设 bibixixi 要减去的数

则要最小化 (S+2ai)24(S+2ai2bi)(S+2ai2+bi)∑(S+2ai)24−(S+2ai2−bi)(S+2ai2+bi)

也就是 b2i∑bi2,当 bibi 全相同的时候取最小值

所以 xixi 减去 (xiS)k(∑xi−S)k 就好了

算出 xixi 后带入表达式计算一下就好了

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>

using namespace std;

const int N=20;

int n,l[N],r[N],a[N][N],vis[30],w[N],S;
double ans,val[N];

inline void calc(){
  double rst=S;
  for(int i=1;i<=n;i++) val[i]=0;
  for(int i=1;i<=n;i++){
    if(!w[i]) continue;
    if(w[i]==1) val[i]=l[i],rst-=l[i];
    else val[i]=r[i],rst-=r[i];
  }
  if(rst<0) return ;
  for(int i=1;i<=n;i++)
    for(int j=i+1;j<=n;j++)
      if(!w[i] && !w[j] && !a[i][j]) return ;
  double tot=0; int cnt=0;
  for(int i=1;i<=n;i++){
    if(w[i]) continue;
    double cur=0; cnt++;
    for(int j=1;j<=n;j++)
      if(w[j] && a[i][j]) cur+=val[j];
    val[i]=cur+rst/2;
    tot+=val[i];
  }
  if(cnt){
    double k=(tot-rst)/cnt;
    for(int i=1;i<=n;i++)
      if(!w[i]) val[i]-=k;
  }
  for(int i=1;i<=n;i++)
    if(val[i]+1e-7<l[i] || val[i]-1e-7>r[i]) return ;
  double cans=0;
  for(int i=1;i<=n;i++)
    for(int j=i+1;j<=n;j++)
      if(a[i][j]) cans+=val[i]*val[j];
  ans=max(ans,cans);
}

void dfs(int x){
  if(x>n) return calc();
  for(int i=0;i<3;i++){
    w[x]=i; dfs(x+1);
  }
}

class BoundedOptimization{
public:
  double maxValue(vector<string> expr,vector<int> lb,vector<int> rb,int maxS){
    n=lb.size(); S=maxS;
    for(int i=1;i<=n;i++) l[i]=lb[i-1],r[i]=rb[i-1];
    string cur;
    for(int i=0;i<expr.size();i++) cur+=expr[i];
    for(int i=0;i<cur.size();i+=3){
      a[cur[i]-'a'+1][cur[i+1]-'a'+1]=a[cur[i+1]-'a'+1][cur[i]-'a'+1]=1;
    }
    dfs(1);
    return ans;
  }
}Main;

int main(){
  vector<string> a={ "ca+fc+fa+d", "b+da+", "dc+c", "b", "+ed+eb+ea" };
  vector<int> lb=   { 10, 11, 12, 13, 14, 15 },rb=  { 15, 16, 17, 18, 19, 20 };
  int mS=85;
  printf("%.9lf\b",Main.maxValue(a,lb,rb,mS));
  for(;;);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值