Riddle(2018 CCPC (秦皇岛站) I 题)
Problem Description
Input?
Output
Sample Input
3
3
1 1 1
5
1 1 2 2 3
10
1 2 3 4 5 6 7 8 9 10
Sample Output
7
15
127
Sample Explanation
題意:有 t 組數據,對于每組數據,給出 n 個數字,最多有 n 個玩具,其中每個數字有兩種含義,要么是一個玩具的重量,要么是一個袋的重量,袋子的重量表示袋子中的玩具的重量,其重量為任意個玩具的重量之和,問最多有多少種方案
思路:
對于不超過 15 個數字的 n 個數字,每個數字有兩種狀態,即要么是表單個玩具重量,要么是表袋內部分玩具的總重,根據前面數字所代表的狀態很容易判斷后面數字代表的狀態,滿足無后效性原則,因此很容易想到可以用狀壓 DP 來解決。
但袋子中玩具的個數無法確定,因此無法用簡單的 1、0 來表示是玩具還是袋子,但由于袋子的重量是由袋子中玩具的重量相加得來,因此可用 1 來表示考慮當前數字,0 表示不考慮當前數字,通過對數字的考慮來進行組合,從而判斷袋子的重量是否合理,例如:101 表示考慮第 1、3 數字時的合法方案數,即第 1、3 個數字可以組成一個袋子,用 f[101] 即可表示組成袋子的方案數,再用 dp[i] 來表示合法方案數。
這樣一來,就有 1<<n? 種狀態,考慮袋子 i 去枚舉狀態?j ,由于袋子 i 中的物品必定屬于袋子,因此不能與狀態?j 有沖突,故有 i&j=0,以此來進行狀態轉移,故有:dp[i|j]+=dp[j]*f[i]
Source Program
#include<iostream> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<cmath> #include<ctime> #include<algorithm> #include<stack> #include<queue> #include<vector> #include<set> #include<map> #define PI acos(-1.0) #define E 1e-6 #define MOD 16007 #define INF 0x3f3f3f3f #define N 16 #define LL long long using namespace std; int a[N]; int f[1<<N];//組成袋子的合法方案數 int dp[1<<N];//合法方案數 int weight[1<<N];//第i種狀態的重量 int main() {int t;scanf("%d",&t);while(t--){int n;scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]);for(int i=0;i<(1<<n);i++){weight[i]=0;f[i]=0;dp[i]=0;}for(int i=1;i<=n;i++)//n位數字for(int j=1;j<(1<<n);j++)//2^n種狀態if( 1<<(i-1) & j )//若第i位是1weight[j]+=a[i];//記錄第j個狀態的重量for(int i=1;i<=n;i++)//n位數字for(int j=1;j<(1<<n);j++)//2^n種狀態if( 1<<(i-1) & j )//若第i位是1if(weight[j]-a[i]==a[i])//如果第j個狀態的重量減去第i個物品的重量等于第i個物品的重量說明選擇第j個狀態是一個合法的袋子f[j]++;for(int i=1;i<(1<<n);i++){//包裹2^n種狀態int k=(1<<n)-1-i;//與i相斥的狀態for(int j=k;;j=(j-1)&k){//選物品的狀態且其不能選為包裹dp[i|j]+=dp[j]*f[i];if(j==0)break;}}printf("%d\n",dp[(1<<n)-1]);}return 0; }?
總結
以上是生活随笔為你收集整理的Riddle(2018 CCPC (秦皇岛站) I 题)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux 下的帮助命令
- 下一篇: Find the most comfor