乍看此题,还以为是扫描线+贪心,每次都扫描出最多的那个站,但是时间复杂度太高,而且写到一半的时候发现了反例. . . . .
接下来开始推式子:
dp[ i ][ j ] = max(dp[ k1 ][ j ],dp[ k2 ][ j -1] + ans[site[ k2 ][j-1]+1][i])。
k1 ∈[j,i],k2 ∈[j-1,i].
site[ i ][ j ]表示的dp[ i ][ j ]这种情况下最右边的洗脑设备的位置.
ans[ i ][ j ]表示 以 k ∈ [ i , j ] 为始发站,经过 j 且不以 j 为终点的客人数量.
好了,理清上面的思路后问题的难点就变成了 如何统计出 ans[ ][ ]。
如果单纯的暴力枚举时间复杂度是o(n^4),二维的线段树倒是可以胜任,但是我忘了怎么写了。。。
然后学姐说可以试一试能否转化成简单的矩阵DP。
设,Map[ i ][ j ]存储的为 i 到 j 的客流量,i >= j 时,Map[ i ][ j ] = 0。
则ans[ x ][ y ] = sigma Map[ i ][ j ] ( x <= i <= y ,y < j <= n)。
接下来可以用 2*n^2 的时间将Map[ i ][ j ]处理成 (1,1) 到 ( i , j )的矩形范围内元素的和。
则 ans[ i ][ j ] = Map[ j ][ n ] - Map[ j ][ j ] - Map[ i-1 ][ n ] + Map[ i-1 ][ j ]。
显然这种方法预处理的时间较高,但查询只需要o(1)。缺点在于不能更新。
对于打印路径只需要在dp的时候记录一下前驱即可,不再赘述。
就这个烂题竟然卡了两天。。。。
#include <iostream> #include <algorithm> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <cmath> #include <stack> #pragma comment(linker, "/STACK:1024000000"); #define EPS (1e-8) #define LL long long int #define ULL unsigned long long int #define _LL __int64 #define _INF 0x3f3f3f3f #define INF 40000000 #define Mod 1000000009 using namespace std; int Map[501][501]; struct N { int site,data,pn,pm; }dp[501][501]; int ans[501][501]; bool path[510]; void dfs(int n,int m) { if(n == 0 || m == 0) return ; if(dp[n][m].pm != m) path[n] = true; dfs(dp[n][m].pn,dp[n][m].pm); } int main() { int n,m,i,j,k,t; scanf("%d %d",&n,&m); memset(Map,0,sizeof(Map)); for(i = 1;i < n; ++i) { for(j = i+1;j <= n; ++j) { scanf("%d",&Map[i][j]); } } for(i = 1;i <= n; ++i) { for(j = 1;j <= n; ++j) { Map[i][j] += Map[i][j-1]; } } for(j = 1;j <= n; ++j) { for(i = 1;i <= n; ++i) { Map[i][j] += Map[i-1][j]; } } memset(ans,0,sizeof(ans)); for(i = 1;i <= n; ++i) { for(j = 1;j <= n; ++j) { ans[i][j] = Map[j][n] - Map[j][j] - Map[i-1][n] + Map[i-1][j]; } } for(i = 0;i <= n; ++i) { dp[i][0].data = 0; dp[i][0].site = 0; } for(i = 1;i <= n; ++i) { for(t = min(i,m),j = 1;j <= t; ++j) { dp[i][j].data = dp[j-1][j-1].data + ans[dp[j-1][j-1].site+1][i]; dp[i][j].site = i; dp[i][j].pn = j-1; dp[i][j].pm = j-1; for(k = j;k <= i; ++k) { if(dp[k][j].data > dp[k][j-1].data + ans[dp[k][j-1].site+1][i]) { if(dp[k][j].data > dp[i][j].data) { dp[i][j] = dp[k][j]; dp[i][j].pn = k; dp[i][j].pm = j; } } else { if(dp[k][j-1].data + ans[dp[k][j-1].site+1][i] > dp[i][j].data) { dp[i][j].data = dp[k][j-1].data + ans[dp[k][j-1].site+1][i]; dp[i][j].site = i; dp[i][j].pn = k; dp[i][j].pm = j-1; } } } } } memset(path,false,sizeof(path)); dfs(n-1,m); printf("%d\n",dp[n][m].data); for(i = 1;i <= n;++i) { if(path[i]) { printf("%d",i); break; } } for(++i;i <= n;++i) { if(path[i]) { printf(" %d",i); } } puts(""); return 0; }
URAL 1900. Brainwashing Device,布布扣,bubuko.com
URAL 1900. Brainwashing Device
原文:http://blog.csdn.net/zmx354/article/details/21278113