[数学] Topcoder SRM560 Div1 1000. BoundedOptimization

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

若存在两个元素 xi,xj x i , x j ,它们都取中间值,且 xixj x i x j 不在式子中,

那么设表达式为 axi+bxj+c a x i + b x j + c ,可以发现最有情况肯定是 xi x i xj x j 达到边界值

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

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

化一下式子得到

ki=1xi(jixj+2ai)2 ∑ i = 1 k x i ( ∑ j ≠ i x j + 2 a i ) 2

S=ki=1ai S = ∑ i = 1 k a i

ki=1xi(Sxi+2ai)2 ∑ i = 1 k x i ( S − x i + 2 a i ) 2

也就是说 xi x i S+2ai2 S + 2 a i 2 最优

但是这样 xi ∑ x i 可能大于 S S ,所以要减小 xi,设 bi b i xi x i 要减去的数

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

也就是 b2i ∑ b i 2 ,当 bi b i 全相同的时候取最小值

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

算出 xi x i 后带入表达式计算一下就好了

#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(;;);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值