POJ 3670 Eating Together
之前一直不过,最后的过的思路如下:
dp[i][j]表示的含义是 到第i位,最高为j的子序列的最长长度。
递推式:
dp[i][1] = dp[i-1][1] + (a[i] == 1?1:0); dp[i][2] = max(dp[i][1], dp[i-1][2]) + (a[i]==2?1:0); dp[i][3] = max3(dp[i][1], dp[i][2], dp[i-1][3]) + (a[i]==3?1:0)
高度为1的,最长只能为之前的,加上本身(如果本身是1则可加,否则不行)(1111_)
高度为2的,为刚才算出的 高1序列最长 与 之前高2序列最长 的最大值 再视情况包含本身。(11111_ 或者 11112_)
高度为3类同。(11111_ 或者 1111222_ 或者 11112222333_)
为什么要算高2时要算 第i位高1 而不是第i-1位呢? 因为。如果当i是1的时候,则dp[i][1]>dp[i-1][1], 同时,dp[i][1]也符合dp[i][2](只是要求最高为2, 不是一定要到2,所以序列111也可以包含在高2的序列内),所以应当选dp[i][1];
那么代码是如何避免 高3 序列包含如 1232123 这样不合法的序列呢?
注意到,每个状态只能选择合并较低状态,或者保持之前状态,或者包含与本状态相当的数(如高2状态只会包含2),所以比本状态小的数在之后是不会进入这个状态序列的。
注意到,当a[i]=2时,原先的高1保持不变,包含a[i]这位的子序列的只可能 加上dp[i][1]后包含在 高2 的状态内。(也可能不包含a[i],情况就是dp[i-1][2]比较大)而高2状态中不可能继续包含1.
同样,a[i]=3时,包含该位的子序列也就跳入了 高3 中,之后高3只可能继续包含3 而不可能包含1 2, 所以不会出现1231 或者 1232这样的情况,只可能是1233.
……还是没说清楚。。
至于为什么是可行的……
i位前高j子序列是什么样的对i位以后没影响。所以任意都可以,自然是选最长的。。。
#include <cstdio> #include <cstring> #include <cstdlib> #define max(a,b) ((a)>(b)?(a):(b)) #define max3(a, b, c) (max((max((a),(b))),(c))) int dp[30010][4]; int a[30010], b[30010]; int n; int cal(int a[]) { int i; dp[0][1] = a[0] == 1?1:0; dp[0][2] = dp[0][1] + a[0] == 2?1:0; dp[0][3] = (max(dp[0][1], dp[0][2])) + (a[0]==3?1:0); for (i = 1; i < n; i++) { dp[i][1] = dp[i-1][1] + (a[i] == 1?1:0); dp[i][2] = max(dp[i][1], dp[i-1][2]) + (a[i]==2?1:0); dp[i][3] = max3(dp[i][1], dp[i][2], dp[i-1][3]) + (a[i]==3?1:0); } int max = 0; for (i = 1; i <= 3; i++) { if (max < dp[n-1][i]) max = dp[n-1][i]; } return max; } int main() { while (~scanf("%d", &n)) { int i; for (i = 0; i < n; i++) { scanf("%d", &a[i]); b[n-1-i] = a[i]; } int max = cal(a); int temp = cal(b); if (max < temp) max = temp; printf("%d\n", n - max); } return 0; }
posted on 2013-05-09 12:44 ShineCheng 阅读(139) 评论(0) 编辑 收藏 举报