IOI的題目很有殺傷力
有n中編號的物品,每種物品有自己的單價,在促銷活動中,第j件物品可以和指定的其他第ni件物品(1<=i<=5)物品進行組合,組合之後,有對應的促銷價格。現在求最小的價格。
1.計算當前最小价格,第ni(1<=i<=5)要麼不與其他物品進行組合促銷,要麼在可以組合促銷的前提下,進行促銷。即爲當前最優解,顯然需要搜索+回溯
2.用六維數組dp[i][j][k][l][m][n](i,j,k,l,m,分別代表5種物品的數量,n(1<=n<=s)表示採用第n中組合的促銷優惠)表示第n種促銷優惠中的購買指定物品的最小价格。
#include<iostream>
#include<string.h>
#include<math.h>
#include<fstream>
#include<algorithm>
#include<stdio.h>
#include<queue>
#include<vector>
using namespace std;
#define MAX 1<<30;
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
typedef struct str_a { int r[5], price; } sale;
int dyna[6][6][6][6][6][101];
int uid[1010], a[5], price[5], mr = 0;
sale list[101]; int s;
int search (int id, int n)
{
int i, j, ans = MAX;
if (id >= s)
{
for (i = 0; i < 5; i++)
if (a[i] > 0) n += a[i] * price[i];
return n;
}
else if (dyna[max(a[0], 0)][max(a[1], 0)][max(a[2], 0)][max(a[3], 0)][max(a[4], 0)][id] >= 0)
return dyna[max(a[0], 0)][max(a[1], 0)][max(a[2], 0)][max(a[3], 0)][max(a[4], 0)][id] + n;
else
{
for (i = 0; i <= 5; i++)
{
for (j = 0; j < 5; j++) a[j] -= (list[id].r[j] * i);
ans = min(ans, search(id + 1, list[id].price * i));
for (j = 0; j < 5; j++) a[j] += (list[id].r[j] * i);
}
dyna[max(a[0], 0)][max(a[1], 0)][max(a[2], 0)][max(a[3], 0)][max(a[4], 0)][id] = ans;
return ans + n;
}
}
int main ()
{
//freopen("data_1170","r",stdin);
int i, j, n, id, amount, pri, g;
memset(dyna, -1, sizeof(dyna));
memset(a, 0, sizeof(a));
memset(price, 0, sizeof(price));
scanf("%d", &n);
for (i = 0; i < n; i++)
{
scanf("%d %d %d", &id, &amount, &pri);
uid[id] = i;
a[i] = amount;
price[i] = pri;
}
scanf("%d", &s);
for (i = 0; i < s; i++)
{
for (j = 0; j < 5; j++)
list[i].r[j] = 0;
scanf("%d", &g);
for (j = 0; j < g; j++)
{
scanf("%d %d", &id, &amount);
list[i].r[uid[id]] = amount;
}
scanf("%d", &list[i].price);
}
printf("%d\n", search(0, 0));
return 0;
}