大理石分割问题
大理石分割問題
有若干塊大理石,其大小及美觀程度不一,為了比較客觀的分割這些大理石,我們需要先給這些大理石一個(gè)評分,評分分為6個(gè)等級,分別用1~6的數(shù)字來表示?,F(xiàn)希望將這些大理石分成兩部分,使每部分的評分之和相同。
輸入:
輸入一行,包括6個(gè)數(shù),分別是每個(gè)等級的大理石的數(shù)量。每種等級的大理石數(shù)量不超過20000.
輸出:
如果這些大理石能否分割成評價(jià)等級之和相同的兩部分,則輸出true,否則輸出false.
方法一:采用二進(jìn)制的解法,看的其他人寫的,沒有太懂原理,想要了解的話可以去看看多重背包的二進(jìn)制解法:
/*poj1014 AC*/ #include<cstdio>long sum,v,tot,i,j; bool f[100000]; long num[7];void Zeroonepack(int weight) {for (long j=v;j>=weight;j--)if (f[j-weight]) f[j]=true; }void Multiplepack(int num,int weight) {long k=1;if(num==1) { Zeroonepack(weight); return;}while(k<num){Zeroonepack(k*weight); //拆分num-=k;k*=2;}if(num) Zeroonepack((num)*weight); //NUM! } int main() {while (1) {tot++;bool b=false;sum=0;for (i=1;i<=6;i++) {scanf("%ld",&num[i]);if(num[i]) b=true;sum+=i*num[i];}if (!b) break; //都為0,breakif (sum%2){printf("Collection #%ld:\nCan't be divided.\n\n",tot);continue;}v=sum/2; //劃分為兩部分for(i=1;i<=v;i++) f[i]=false;f[0]=true;for (i=1;i<=6;i++){Multiplepack(num[i],i);for(j=1;j<=v;j++){ int a=f[j];printf("%d\t",f[j]);}printf("\n");}if(f[v]){int b=1;printf("Collection #%ld:\nCan be divided.\n\n",tot);}else{int b=0;printf("Collection #%ld:\nCan't be divided.\n\n",tot);}} }方法二:比較簡單的遞歸回溯方法,對于解空間樹與搜索空間樹都能夠很好地畫出來,也能很快理解原理,代碼如下:(如轉(zhuǎn)載需標(biāo)明出處)
#include<stdio.h>int counts[7]; int flag = 0; void solve(int half,int fetch) {if (half == fetch) {flag = 1;return;}if (fetch < half) {for (int i = 1; i <= 6; i++) {if (counts[i]) {counts[i]--;fetch += i;if (fetch > half) {counts[i]++;fetch -= i;continue;}solve(half, fetch);}}}}int main() {int tCase = 1;while (1) {int sum = 0;for (int i = 1; i <= 6; i++) {scanf("%d",&counts[i]);sum += counts[i]*i;}printf("Collection # %d:\n",tCase++);if (sum % 2){printf("Can't be divided.\n\n");continue;}flag = 0;solve(sum / 2, 0);if (flag) {printf("Can be divided.\n\n");} else {printf("Can't be divided.\n\n");}}return 0; }運(yùn)行截圖如下:
總結(jié)
- 上一篇: 跳跃问题(Java)
- 下一篇: 木材切割问题