好神的思路- - 居然用图论转姿势化式子
因为是很多两个变量的积加起来,那么转化成一张图,就是右边的两个点的值乘积,求个和。
设想最后得到一个答案,如果某两个点不相邻,并且这两个点没有取到最值,点A周围点的权值和是suma,点B周围点的权值和是sumb。
那么如果suma>sumb,那么可以增加A的值减少B的值使得答案更大,然后A,B中肯定一个会达到最值。
所以,没有取到最值的点肯定是个团。就可以3^15枚举哪些取得最大值,哪些最小值,哪些没有取到最值。
对于没有取到最值的点,假设剩下的可分配价值是M,每个点周围sumi,每个点的价值是vi,k是团的个数
那么可以列出式子:对每个i求和(vi*(sumi+(M-vi)/2)) 就是求这个的最大值,M-vi是团中剩下点的权值和,除以2是因为会重复算两次。
然后要求在sum(vi)=M的条件下,求上式的极值,用拉格朗日乘数法带入求偏导,得到 vi = sumi + (M - 求和(sumi))/k
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstring>
using namespace std;
class BoundedOptimization {
public:
double maxValue(vector<string> , vector<int> , vector<int> , int);
};
int gg[55][55];
double val[55];
double BoundedOptimization::maxValue(vector<string> expr,
vector<int> lowerBound, vector<int> upperBound, int maxSum) {
int i, j, k;
int ch, nch, chmx, chmn;
string ex;
double ans, p;
bool flag;
ex.clear();
for (i = 0; i < expr.size(); ++i)
ex = ex + expr[i];
memset(gg, 0, sizeof(gg));
for (i = 0; i < ex.size(); i += 3) {
gg[ex[i] - 'a'][ex[i + 1] - 'a'] = 1;
gg[ex[i + 1] - 'a'][ex[i] - 'a'] = 1;
}
int n = lowerBound.size();
ans = 0;
for (nch = 0; nch < (1 << n); ++nch) {
flag = true;
for (i = 0; i < n; ++i) {
if ((nch & (1 << i)) == 0)
continue;
for (j = i + 1; j < n; ++j) {
if ((nch & (1 << j)) == 0)
continue;
if (gg[i][j] == 0)
flag = false;
}
}
if (!flag)
continue;
ch = ((1 << n) - 1) ^ nch;
for (chmx = ch;; chmx = ((chmx - 1) & ch)) {
flag = true;
chmn = (ch ^ chmx);
double M = maxSum;
k = 0;
for (i = 0; i < n; ++i) {
if (chmx & (1 << i)) {
val[i] = upperBound[i];
M -= upperBound[i];
} else if (chmn & (1 << i)) {
val[i] = lowerBound[i];
M -= lowerBound[i];
} else
k++;
}
if (M < 0) {
if (chmx == 0)
break;
continue;
}
double suma = 0;
for (i = 0; i < n; ++i) {
if (nch & (1 << i)) {
for (j = 0; j < n; ++j) {
if (gg[i][j] == 0)
continue;
if (chmx & (1 << j))
suma += upperBound[j];
else if (chmn & (1 << j))
suma += lowerBound[j];
}
}
}
double t = (M - suma) / k;
for (i = 0; i < n; ++i) {
if (nch & (1 << i)) {
double a = 0;
for (j = 0; j < n; ++j) {
if (gg[i][j] == 0)
continue;
if (chmx & (1 << j))
a += upperBound[j];
else if (chmn & (1 << j))
a += lowerBound[j];
}
val[i] = a + t;
if (val[i] < lowerBound[i] || val[i] > upperBound[i])
flag = false;
}
}
if (!flag) {
if (chmx == 0)
break;
continue;
}
p = 0;
for (i = 0; i < n; ++i) {
for (j = i + 1; j < n; ++j) {
if (gg[i][j])
p += val[i] * val[j];
}
}
ans = max(ans, p);
if (chmx == 0)
break;
}
}
return ans;
}