题意:
给你n件物品,三个参数描述该物品,编号,数量(<=5),每件价格。 n <= 5
然后给你s种方案,第一个数位商品种类对数,然后是该商品型号,数量,最后一个数是该方案价格。
求把所有物品买完最低的价格。
算法1:
商品种类很少,<= 5
开个五维数组
int dp[5][5][5][5][5],dp[a][b][c][d][e][f],表示第1中物品买a件,第2种物品买b件,。。,第5种物品买f件所需要价格
然后DFS枚举每一种方案,记忆化搜索,即可以算出最优解。
View Code
#include<stdio.h> #include<stdlib.h> #include<string.h> struct node { int n[6]; //保存每种商品数量 int price; //保存该种方案的价格 }plan[120]; const int inf = 0x3f3f3f3f; int num[10]; //保存要购买的数量 int M; //保存所有方案 int code[1100]; //映射下标 int F[6][6][6][6][6]; //表示1号商品购买六,2号商品购买六,。。。5号商品购买六种,所花的钱 int DFS( int n1, int n2, int n3, int n4, int n5) { if( F[n1][n2][n3][n4][n5] != -1) return F[n1][n2][n3][n4][n5]; //记忆化搜索 int Minx = inf; for( int i = 1; i <= M; i++) { if( n1 >= plan[i].n[1] && n2 >= plan[i].n[2] && n3 >= plan[i].n[3] && n4 >= plan[i].n[4] && n5 >= plan[i].n[5]) { int temp = DFS(n1 - plan[i].n[1], n2 - plan[i].n[2], n3 - plan[i].n[3], n4 - plan[i].n[4], n5 - plan[i].n[5]) + plan[i].price; if( temp < Minx ) Minx = temp; } } F[n1][n2][n3][n4][n5] = Minx; return F[n1][n2][n3][n4][n5]; } int main( ) { int N, c, k, p, i, t; while( scanf("%d",&N) != EOF ) { memset(plan, 0, sizeof(plan)); memset(F, -1, sizeof(F)); F[0][0][0][0][0] = 0; for(i = 1; i <= N; i++) { scanf("%d%d%d",&c, &k, &p);//读入标号,数量,价格 code[c] = i; //映射下标 num[i] = k; //保存要购买的数量 //第i种方案 plan[i].price = p; plan[i].n[code[c]] = 1; } scanf("%d",&M); M += N; for( ; i <= M; i++) { scanf("%d",&t); for( int j = 1; j <= t; j++) { scanf("%d%d",&c, &k); //读入商品标号与数量 plan[i].n[code[c]] = k; } scanf("%d",&p); //读入组合后的价格 plan[i].price = p; } printf("%d\n",DFS(num[1], num[2], num[3], num[4], num[5])); } return 0; }
算法2:
状态压缩:
最大为5,我们可以用6进制12345来表示第1中方案选择了5件,第2种方案选择了2件。。。
把十进制转为六进制。。
dp[state]表示该状态最优解。。
最后枚举state既可。。
奇葩。。神奇的状态压缩,就怕你想不到
View Code
#include<stdio.h> #include<string.h> #include<stdlib.h> //li int dp[11000]; int num[20]; //保存数量 int price[20]; //保存价格 int code[1100]; int st[10] = {1, 6, 36, 216, 1296, 7776, 46656 }; int state;//总的状态i struct node { int s; //该方案的状态值 int p; //该方案话费 }plan[110]; int N, M; const int inf = 0x3f3f3f3f; //十进制转为六进制 bool jugde( int a, int b) { for( int i = 0; i < N; i++) { if( (a % 6 + b % 6) > num[i] ) return false; a = a / 6; b = b / 6; } return true; } int sum( int x) { int sumx = 0; for( int i = 0; i < N; i++) { sumx += (x % 6) * price[i]; x = x / 6; } return sumx; } int main( ) { int p, k, c, t; while( scanf("%d",&N) != EOF) { state = 0; memset(plan, 0, sizeof(plan)); for( int i = 0; i < N; i++) { scanf("%d%d%d",&c, &k, &p); code[c] = i; num[i] = k; price[i] = p; state += st[i] * k; } scanf("%d",&M); for( int i = 1; i <= M; i++) { scanf("%d",&t); for( int j = 1; j <= t; j++) { scanf("%d%d",&c,&k); plan[i].s += st[code[c]] * k; } scanf("%d",&p); plan[i].p = p; } for( int i = 1; i <= state; i++) dp[i] = inf; dp[0] = 0; for( int j = 1; j <= M; j++) { for( int i = 0; i <= state; i++) { if( i + plan[j].s <= state && jugde(i, plan[j].s)) { if( dp[i + plan[j].s] > dp[i] + plan[j].p && dp[i] != inf) dp[i + plan[j].s] = dp[i] + plan[j].p; } } } int ans = inf; for( int x = 0; x <= state; x++) { int t = sum(state - x ); if( ans > t + dp[x] ) ans = t + dp[x]; } printf("%d\n", ans); } return 0; }