首页 > 代码库 > hdoj 1059 Dividing 【多重背包】||【优化母函数】
hdoj 1059 Dividing 【多重背包】||【优化母函数】
题意:每一种弹珠(marble)的都有各自的价值,第一种为1, 第二种为2,。。,给出你每种弹珠的数量,求能不能将价值总和均分。
策略:rt;
这道题比赛的时候没有想到用母函数,就用了多重背包来解,之后递交的时候时间居然超600ms,我再一看递交排行都是0ms(⊙﹏⊙b汗)。看到讨论区有人说母函数也可以,于是就写了个普通的,可惜TL了。果然还是需要优化啊。。。于是游来游去果然0ms(O(∩_∩)O哈哈哈~)。
说一下0秒的思路,因为只是问能不能均分,所以我们没有必要找种类数,找到了就定义为1好了,而且,从目标开始找往下找也会增加速度。不多说,直接上代码。
代码1(多重背包)(609ms):
#include <stdio.h> #include <string.h> int s[6]; int dp[120050]; int main() { int v = 1; while(scanf("%d%d%d%d%d%d", &s[0], &s[1], &s[2], &s[3], &s[4], &s[5]) == 6){ int sum = 0, c[20000], w[20000], i, j; for(i = 0; i < 6; i ++){ sum += s[i]*(i+1); } if(sum == 0) break; printf("Collection #%d:\n", v++); if(sum%2){ printf("Can't be divided.\n\n"); continue; } else{ sum/=2; for(i = 1; i <= sum; i++) dp[i] = -120050; dp[0] = 0; int tot = 0; for(i = 0; i < 6; i ++){ int l = 1; while(s[i] >= l){ c[tot] = l*(i+1); w[tot++] = l*(i+1); s[i] -= l; l<<=1; } if(s[i]){ c[tot] = s[i]*(i+1); w[tot++] = s[i]*(i+1); } } for(i = 0; i < tot; i ++){ for(j = sum; j >= c[i]; j --){ if(dp[j] < dp[j-c[i]]+w[i]) dp[j] = dp[j-c[i]]+w[i];// printf("%d..%d\n", dp[j], j); } } if(dp[sum] > 0) printf("Can be divided.\n"); else printf("Can't be divided.\n"); printf("\n"); } } }代码2(母函数优化)0ms:
#include <stdio.h> #include <string.h> int c1[120000]; int main() { int s[7], i, j, k, v = 1; while(1){ int sum = 0; for(i = 1; i <= 6; i ++){ scanf("%d", &s[i]); sum += (s[i]%60)*i; } if(sum == 0) break; printf("Collection #%d:\n", v++); if(sum & 1){ printf("Can't be divided.\n\n"); continue; } sum >>=1; memset(c1, 0, sizeof(c1)); for(i = 0; i <= sum&&i <= s[i]; i ++){ //第一种弹珠 c1[i] = 1; } for(i = 2; i <= 6; i ++){ //2~6 if(s[i] == 0) continue; //如果该种弹珠数目为0,不没有必要往下了,去掉这一句,要15ms for(j = sum; j >= 0; j --){//从头往下找 if(c1[j] == 0) continue; //如果这个不能达到,那么由他组成的也不能达到所以就不用找了 for(k = i; k + j <= sum&&k <= s[i]*i; k+=i){ c1[j+k] = 1; } } if(c1[sum]) printf("Can be divided.\n\n"); else printf("Can't be divided.\n\n"); } return 0; }
代码3(母函数)31ms:(不懂为什么,以后学到了类似的知识点再来看)
#include <stdio.h> #include <string.h> int c1[120000], c2[120000]; int main() { int s[7], i, j, k, v = 1; while(1){ int sum = 0; for(i = 1; i <= 6; i ++){ scanf("%d", &s[i]); sum += (s[i]%60)*i; //与传统的其他没区别,只有这一点s[i]%60有区别,难道说是有规律吗? } if(sum == 0) break; printf("Collection #%d:\n", v++); if(sum & 1){ printf("Can't be divided.\n\n"); continue; } sum >>=1; memset(c1, 0, sizeof(c1)); memset(c2, 0, sizeof(c2)); c1[0] = 1; for(i = 1; i <= sum&&i <= s[i]; i ++){ c1[i] = 1; } for(i = 2; i <= 6; i ++){ if(s[i] == 0) continue; for(j = 0; j <= sum; j ++){ for(k = 0; k + j <= sum&&k <= s[i]*i; k+=i){ c2[j+k] += c1[j]; } } for(j = 0; j <= sum; j ++){ c1[j] = c2[j]; c2[j] = 0; } } if(c1[sum]) printf("Can be divided.\n\n"); else printf("Can't be divided.\n\n"); } return 0; }
题目链接:点击打开链接
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。