您的位置:首页 > Web前端

USACO Shopping Offers 解题报告

2013-04-06 19:29 323 查看
这道题刚开始用搜索做的,即遍历每种特惠的可能次数,最后取最省的组合。虽然用到了剪枝(当当前的费用已经超过了当前最省的组合,就不必接着考虑后面的特惠了),但是仍然效率特别低,在遇到后面的测试点的时候程序就无止境地跑下去了。

后来看到网上说用动态规划,因为最多只有5种商品,每种商品最多买5个,所以状态总数特别少,只有6^5=7776。所以用动态规划把表填了就好。

简单总结:

1.每次做题对状态总数要有个大致的估计,像最近做的这几道题,如果状态空间很小(运算重量级万或运算轻量级十万以下),直接枚举就好(会通过动态规划等方法用到之前的状态)。

2.好的算法和差的算法的运行效率有天壤之别。之前的搜索的方法面对稍大的数据,就永远等不出结果了。而动态规划的方法仍然是blazingly fast.

代码如下:

/*
ID: thestor1
LANG: C++
TASK: shopping
*/
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cassert>
#include <string>
#include <algorithm>
#include <stack>
#include <set>
#include <queue>
#include <map>

using namespace std;

const int P = 5;
const int S = 99;

int main()
{
FILE *fin  = fopen ("shopping.in", "r");
FILE *fout = fopen ("shopping.out", "w");
//freopen("log.txt", "w", stdout);

int s;
fscanf(fin, "%d", &s);

map<int, int> cid;
int sos[S][6] = {0};
int id = 0;
for(int i = 0; i < s; ++i)
{
int n;
fscanf(fin, "%d", &n);
for(int j = 0; j < n; ++j)
{
int c;
fscanf(fin, "%d", &c);
if(cid.find(c) == cid.end())
{
cid[c] = id;
id++;
}
fscanf(fin, "%d", &sos[i][cid[c]]);
}
fscanf(fin, "%d", &sos[i][5]);
}

int b;
fscanf(fin, "%d", &b);
int require[P] = {0};
int price[P] = {0};
for(int i = 0; i < b; ++i)
{
int c;
fscanf(fin, "%d", &c);
if(cid.find(c) == cid.end())
{
cid[c] = id;
id++;
}
fscanf(fin, "%d", &require[cid[c]]);
fscanf(fin, "%d", &price[cid[c]]);
}
assert(id <= 5);

int f[6][6][6][6][6];
int num[5] = {0};
for(num[0] = 0; num[0] <= require[0]; ++num[0])
{
for(num[1] = 0; num[1] <= require[1]; ++num[1])
{
for(num[2] = 0; num[2] <= require[2]; ++num[2])
{
for(num[3] = 0; num[3] <= require[3]; ++num[3])
{
for(num[4] = 0; num[4] <= require[4]; ++num[4])
{
if(!num[0] && !num[1] && !num[2] && !num[3] && !num[4])
{
f[0][0][0][0][0] = 0;
continue;
}
f[num[0]][num[1]][num[2]][num[3]][num[4]] = -1;
for(int i = 0; i < 5; ++i)
{
int nnum[5];
for(int j = 0; j < 5; ++j)
{
nnum[j] = num[j];
}
if(num[i] > 0)
{
nnum[i] = num[i] - 1;
if(f[num[0]][num[1]][num[2]][num[3]][num[4]] < 0
|| f[nnum[0]][nnum[1]][nnum[2]][nnum[3]][nnum[4]] + price[i]
< f[num[0]][num[1]][num[2]][num[3]][num[4]])
{
f[num[0]][num[1]][num[2]][num[3]][num[4]] =
f[nnum[0]][nnum[1]][nnum[2]][nnum[3]][nnum[4]] + price[i];
}
}
}
for(int i = 0; i < s; ++i)
{
bool possible = true;
for(int j = 0; j < 5; ++j)
{
if(sos[i][j] > num[j])
{
possible = false;
break;
}
}
if(!possible)
{
continue;
}
int nnum[5];
for(int j = 0; j < 5; ++j)
{
nnum[j] = num[j] - sos[i][j];
}
assert(f[num[0]][num[1]][num[2]][num[3]][num[4]] > 0);
if(f[nnum[0]][nnum[1]][nnum[2]][nnum[3]][nnum[4]] + sos[i][5]
< f[num[0]][num[1]][num[2]][num[3]][num[4]])
{
f[num[0]][num[1]][num[2]][num[3]][num[4]] =
f[nnum[0]][nnum[1]][nnum[2]][nnum[3]][nnum[4]] + sos[i][5];
}
}
}
}
}
}
}
fprintf(fout, "%d\n", f[require[0]][require[1]][require[2]][require[3]][require[4]]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: