USACO 3.3.2 Shopping Offers解题报告

写在前面:因为之前没写的C++的USACO Training的解题报告太多……所以就不写了,要是想要代码可以联系我:xiedong_1993@foxmail.com

这题就是传说中的五维背包,其实写起来难度不大。但是我写的时候可以说是遇到了重重困难。因为我对C++的掌握还不如Pascal,所以很多东西写的不是很熟。这题有一个很大的问题就在于,最后有用的只有五种物品,但是物品的编号却又很多。处理的方法有几种,一种是离散化,但是这个太SB了。。为了处理这么弱的数据还要排序重标号实在得不偿失。另一种是直接就标号,但是面临的问题就是,需要用的五种标号在能标之前就要被用到,就涉及到了一个问题,如何略过前面的部分,先处理后面的。。

两种方案:1、全读到一个数组里面,然后再将这个数组重新处理。这个方法可以是可以,但是浪费时间也浪费空间。

                   2、先直接不读前面的部分,读后面的,然后关文件,再开一遍,把前面的读进来。我这里用的就是后者。

我们知道pascal处理这个问题很简答,只要reset一下就好。但是C++需要先关闭文件,再全部重新关联一遍。因此学会了fclose……fclose之后重新freopen就好了。

还有更悲剧的,pascal中跳过一样直接readln就好,但是C++貌似读个回车是不好使的。。。还得挨个字符跳,不知有没有好的其他的方法……

我的方法:

for (int i = 0; i < m; i++)
{
     char ch = '\0';
     while (ch != '\n') scanf("%c", &ch);
}

这两个问题处理了之后依旧卡了很长时间,很简单……遇到一个USACO的exit code,我最开始觉得可能是那块的库他没有,但是后来发现是超内存了。。。(注意:以后如果在USACO遇到exit code 127就是超内存了)剩下的DP就简单了,dp[i1][i2][i3][i4][i5]就是五样东西各这些个的时候需要的最少花费。

代码:

/*
TASK:shopping
LANG:C++
*/
#include <iostream>
#include <fstream>
#include <climits>
using namespace std;

int n,m;
int no[1200], cost[120];
int need[6];
int data[120][6];
int dp[14][14][14][14][14];
const int inf = INT_MAX;

void init()
{
    scanf("%d\n", &m);
   	for (int i = 0; i < m; i++)
   	{
   		char ch = '\0';
   		while (ch != '\n') scanf("%c", &ch);
   	}
    scanf("%d", &n);
    for (int i = 0; i < 120; i++) no[i] = -1;
    for (int i = 0; i < n; i++)
    {
        int x,y,w;
        scanf("%d%d%d", &x, &y, &w);
        no[x] = i; need[i] = y;
        cost[m + i] = w; data[m + i][i] = 1;
    }
    fclose(stdin);
    freopen("shopping.in", "r", stdin);
    scanf("%d", &m);
    for (int i = 0; i < m; i++)
    {
    	int num;
    	scanf("%d", &num);
        for (int j = 0; j < num; j++)
        {
        	int x,y;
        	scanf("%d%d", &x, &y);
            if (no[x] != -1)
                data[i][no[x]] += y;
        }
        scanf("%d", &cost[i]);
    }
    m += n;
    for (int i1 = 0; i1 <= need[0]; i1++)
        for (int i2 = 0; i2 <= need[1]; i2++)
            for (int i3 = 0; i3 <= need[2]; i3++)
                for (int i4 = 0; i4 <= need[3]; i4++)
                    for (int i5 = 0; i5 <= need[4]; i5++)
                        dp[i1][i2][i3][i4][i5] = inf;
}

void solve()
{
    dp[0][0][0][0][0] = 0;
    for (int i1 = 0; i1 <= need[0]; i1++)
        for (int i2 = 0; i2 <= need[1]; i2++)
            for (int i3 = 0; i3 <= need[2]; i3++)
                for (int i4 = 0; i4 <= need[3]; i4++)
                    for (int i5 = 0; i5 <= need[4]; i5++)
                        if (dp[i1][i2][i3][i4][i5] < inf)
                            for (int i = 0; i < m; i++)
                            {
                                int t1 = i1 + data[i][0];
                                int t2 = i2 + data[i][1];
                                int t3 = i3 + data[i][2];
                                int t4 = i4 + data[i][3];
                                int t5 = i5 + data[i][4];
                                dp[t1][t2][t3][t4][t5] = min(dp[t1][t2][t3][t4][t5], dp[i1][i2][i3][i4][i5] + cost[i]);
                            }
}

void print()
{
    printf("%d\n", dp[need[0]][need[1]][need[2]][need[3]][need[4]]);
}

int main()
{
    freopen("shopping.in", "r", stdin);
    freopen("shopping.out", "w", stdout);

    init();
    solve();
    print();

    return 0;
}

转载于:https://www.cnblogs.com/Skyprophet/archive/2011/05/23/2054698.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值