题目链接:
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3375
题目大意:题目规定有三个变量,point,Iv,tv,让我们一个一个地选择n个地方种的某个地方,然后这个地方里面有两种宝物x,y可取,x宝物有xi个,可以让tv增加ai,y宝物有yi个,可以让lv增加bi。选择x,则point += lv,tv += ai,为了防止混乱带来思维复杂度地增加,我用xv代替lv,yv代替tv,这样就好看多了。那么选择x则point += xv,yv += ai,选择y,则point += yv,xv += bi;问最后获得最大point。
InPut:
1
1 2 1 1
3
2 2 2 2
2 2 2 2
2 2 2 2
3
2 2 1 1
2 2 1 2
2 2 2 1
OutPut:
2
72
32
题目大意:题目规定有三个变量,point,Iv,tv,让我们一个一个地选择n个地方种的某个地方,然后这个地方里面有两种宝物x,y可取,x宝物有xi个,可以让tv增加ai,y宝物有yi个,可以让lv增加bi。选择x,则point += lv,tv += ai,为了防止混乱带来思维复杂度地增加,我用xv代替lv,yv代替tv,这样就好看多了。那么选择x则point += xv,yv += ai,选择y,则point += yv,xv += bi;问最后获得最大point。
解题思路:这题初看上去很复杂,但其实想好几点就很简单了。1、,本次选择某个城市,xv必定增加xi*bi,yv必定增加yi*ai,由于后面选择每个地方都要执行point += yv或者point += xv,那么这增加的xv和yv对后面的选择都会有影响,我们可以在前面就考虑对后面选择的影响。 2、选择城市是一步,选择好城市后里面的宝物如何选择才能让本次的point增加最大呢?这个贪心就好,我yy了一个结论,cnt = xi * yi,maxPoint = max(cntx * ai + cnty * bi)(cntx + cnty == cnt) .这个maxPoint是选择城市后增加的,对后面的不会有影响。可以认为选择城市和选择宝物是独立,那么我们可以预处理线算出每个点maxPoint。 3、选择城市可以用状态压缩来做,选择了某些特定的城市后,已经在后面的影响考虑在内,那么dp[i]就可以表示选择了城市编号压缩后为i的最大point。考虑好这三点之后就可以用类似于TSP的转移方法进行DP.
InPut:
1
1 2 1 1
3
2 2 2 2
2 2 2 2
2 2 2 2
3
2 2 1 1
2 2 1 2
2 2 2 1
OutPut:
2
72
32
#include <stdio.h>
#include <string.h>
#define MAX (1<<17)
#define int64 long long
#define max(a,b) ((a)>(b)?(a):(b))
struct node {
int64 a, x, b, y;
} arr[MAX];
int n, m, ans;
int64 totx,toty;
int64 dp[MAX], val[MAX];
void Initial() {
memset(val, 0, sizeof (val));
memset(dp, 0, sizeof (dp));
for (int i = 0; i < n; ++i) {
int64 mmax = 0,cnt = arr[i].x * arr[i].y;
for (int j = 0; j <= cnt; ++j)
mmax = max(mmax,arr[i].a*j+arr[i].b*(cnt-j));
val[i] = mmax;
//printf("i = %d %d\n",i,mmax);
}
}
int Solve_DP() {
int i, j, k, st, cnt;
int64 xv, yv, po, mmax,sumx,sumy;
for (i = 0; i < n; ++i) {
st = (1<<i);
xv = yv = po = 0;
po = val[i];
xv = arr[i].a * arr[i].x;
yv = arr[i].b * arr[i].y;
po += yv * (totx - arr[i].x) + xv * (toty - arr[i].y);
dp[st] = po;
}
for (i = 1; i < (1 << n); ++i) {
cnt = n,sumx= sumy = 0;
for (j = 0; j < n; ++j)
if (((i >> j) & 1) == 0)
sumx += arr[j].x ,sumy += arr[j].y;
for (j = 0; j < n; ++j) {
if (((i >> j) & 1) == 0) {
st = (i | (1 << j));
xv = yv = po = 0;
po = val[j];
xv = arr[j].a * arr[j].x;
yv = arr[j].b * arr[j].y;
sumx -= arr[j].x ,sumy -= arr[j].y;
po += xv * sumy + yv * sumx;
dp[st] = max(dp[i] + po, dp[st]);
sumx += arr[j].x ,sumy += arr[j].y;
}
}
}
}
int main() {
int i, j, k;
while (scanf("%d", &n) != EOF) {
totx = toty = 0;
for (i = 0; i < n; ++i) {
scanf("%lld%lld%lld%lld", &arr[i].a, &arr[i].b, &arr[i].x, &arr[i].y);
totx += arr[i].x ,toty += arr[i].y;
}
Initial();
Solve_DP();
//for (i = 0; i < (1<<n) ; ++i)
// printf("i = %d val = %d\n",i,dp[i]);
printf("%lld\n", dp[(1 << n) - 1]);
}
}
本文ZeroClock原创,但可以转载,因为我们是兄弟。