POJ 1036 Gangsters DP 多解

来源:互联网 发布:java spring框架 入门 编辑:程序博客网 时间:2024/06/04 18:29

题意:一群匪徒要进入一个酒店。酒店的门有k+1个状态,每个匪徒的参数是:进入时间,符合的状态,携带的钱。

酒店的门刚开始状态0,问最多这个酒店能得到的钱数。

 

思路1:dp[i][j]表示时间0-i之间,门的状态为j时所能获得的最大利益

转移方程 :dp[i][j]=max(dp[i-1][j],dp[i-1][j-1],dp[i-1][j+1])

 

因为转移i只跟i-1有关,所以可以用滚动数组dp[2][k]

有一个处理边界的好方法:

j的范围 0 —k,不妨向右移动1位,并保证0,k+2时的状态为0

代码1:

View Code
//O(k*t)#include<stdio.h>#include<string.h>int max(int a, int b) { return a > b ? a : b;}int tt[103], s[103], p[103], dp[2][103], a[30004][103];int main(){    int i, j;    int n, k, t;    while( ~scanf("%d%d%d", &n, &k, &t))    {        for(i = 1; i <= n; i++)            scanf("%d", &tt[i]);        for(i = 1; i <= n; i++)            scanf("%d", &p[i]);        for(i = 1; i <= n; i++)            scanf("%d", &s[i]);        memset(dp, 0, sizeof(dp));        memset(a, 0, sizeof(a));        for(i = 1; i <= n; i++)             if(tt[i] >= s[i])  //把一定不能进入的删去,它会影响状态转移                               //保证0,k+2时的状态为0            a[tt[i]][s[i]+1] += p[i];        for(i = 1; i <= t; i++)            for(j = 1; j <= k+1 && j <= i+1; j++)                dp[i&1][j] = max( dp[(i-1)&1][j+1], max(dp[(i-1)&1][j-1], dp[(i-1)&1][j]) ) + a[i][j];        int ans = 0;        for(i = 1; i <= k+1; i++)            ans = max(ans, dp[t&1][i]);        printf("%d\n", ans);    }    return 0;}

 

代码2:

View Code
//O(k*n)#include<stdio.h>#include<string.h>int max(int a, int b) { return a > b ? a : b;}int tt[103], s[103], p[103], dp[30003][103];int main(){    int i, j;    int n, k, t;    while( ~scanf("%d%d%d", &n, &k, &t))    {        for(i = 1; i <= n; i++)            scanf("%d", &tt[i]);        for(i = 1; i <= n; i++)            scanf("%d", &p[i]);        for(i = 1; i <= n; i++)            scanf("%d", &s[i]);        memset(dp, 0, sizeof(dp));        for(i = 1; i <= n; i++)            if(tt[i] >= s[i]) //同代码1            dp[tt[i]][s[i]+1] += p[i];        for(i = 1; i <= t; i++)            for(j = 1; j <= k+1 && j <= i+1; j++)                dp[i][j] += max( dp[(i-1)][j+1], max(dp[(i-1)][j-1], dp[(i-1)][j]) );        int ans = 0;        for(i = 1; i <= k+1; i++)            ans = max(ans, dp[t][i]);        printf("%d\n", ans);    }    return 0;}

 

思路2:

仔细一想思路1发现dp数组中时间(t)那一维的空间有很多不必要的操作,因此我们可以将数组的这一维优化到人数(n)。

先将n个人按时间从小到大排序。

 

dp[i][j]表示进行到第i个人,门的状态为j时所获得的最大利益

其实这里的思想是单调队列优化,这样1->2->3->....->n递推下去,。

View Code
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;struct node{    int t, p, s;}g[103];int max(int a, int b) { return a > b ? a : b;}int abs(int a) { return a > 0 ? a : -a; }bool cmp(node a, node b){    return a.t < b.t;}int dp[103][103];int main(){    int i, j;    int n, k, t;    while( ~scanf("%d%d%d", &n, &k, &t))    {        for(i = 1; i <= n; i++)            scanf("%d", &g[i].t);        for(i = 1; i <= n; i++)            scanf("%d", &g[i].p);        for(i = 1; i <= n; i++)            scanf("%d", &g[i].s);        sort(g+1, g+n+1, cmp);        memset(dp, -1, sizeof(dp));        g[0].s = g[0].t = 0;        dp[0][0] = 0;        for(i = 0; i < n; i++)        {            for(j = 0; j <= k; j++)            {                if(dp[i][j] == -1) continue;                for(int u = 0; u <= k; u++)                    if(abs(j-u) <= g[i+1].t - g[i].t)                        dp[i+1][u] = max(dp[i+1][u], dp[i][j]);            }             if(dp[i+1][g[i+1].s] != -1)                    dp[i+1][g[i+1].s] += g[i+1].p;        }        int ans = -1;        for(i = 0; i <= k; i++)            ans = max(ans, dp[n][i]);        printf("%d\n", ans);    }    return 0;}

 

以上的情况,还可以再优化

用dp[i]表示表示进行到第i个人所获得的最大利益

递推做了改变, i的状态可以是从 0---(i-1)这些状态推过来

View Code
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int ABS(int a) { return a > 0 ? a : -a; }int max(int a, int b) { return a > b ? a : b; }struct node{   int t,p,s;}g[101];bool cmp(node a, node b){   return a.t<b.t;}int dp[105];int main(){       int i,j,k,p,q,m,n,t;    while(scanf("%d%d%d", &n, &k, &t)!=-1)    {        memset(dp, 0, sizeof(dp));        for(i = 0; i < n; i++)            scanf("%d", &g[i].t);        for(i = 0; i < n; i++)           scanf("%d", &g[i].p);        for(i = 0; i < n; i++)           scanf("%d", &g[i].s);        sort(g, g+n, cmp);       for(i=0;i<n;i++)       {            dp[i] = (g[i].t>=g[i].s)? g[i].p : 0;            for(j = 0; j < i; j++)            {                if(!dp[j]) continue;                if(ABS(g[i].s-g[j].s) > g[i].t-g[j].t) continue;                dp[i] = max(dp[i], dp[j]+g[i].p);            }       }       int ans = 0;       for(i = 0; i < n; i++)           ans = max(ans, dp[i]);       printf("%d\n",ans);    }    return 0;}