解题思路:这题初看上去很复杂,但其实想好几点就很简单了。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.
#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原创,但可以转载,因为我们是兄弟。