zoukankan      html  css  js  c++  java
  • 「背包」Market

    题目大意:

    给定(n)个物品,有价格、价值、可购买时间三个属性,给定(m)个查询,有购买时间、预算两个属性。显然的是只有当购买的时间大于一个物品的可购买时间时,这个物品才可以买。求每次查询能买到最大价值。

    输入样例

    5 2
    5 5 4
    1 3 1
    3 4 3
    6 2 2
    4 3 2
    3 8
    5 9
    

    输出样例

    10
    12
    

    数据范围

    反思

    想来想去,还是写一下这道很搞我心态的题。考试的时候20min砍掉T1,30min上对拍,然后将近2h全扔在这道题上了。主要是写着写着就好像上头了,总觉得这么简单的题说什么也要A了它,但是无论怎样都是感觉跟“正解”差一点点(然而下来发现正解的复杂度就是很迷),然后就一直死磕,最后发现暴力是挂的,爆了零。而且后面两道题也都没留时间,T4 10min打了个60分暴力结果最裸的30分挂了,T3 干脆连暴力都没打完。

    感觉都这时候了还犯这种决策性失误有点说不过去,而且连暴力都打挂是更说不过去的...可能也跟昨天两次考试全部原地爆炸的梦幻开局有关系吧,心态太浮躁,太急功近利了。

    还是稳一点吧,就我这种水平也不求翻盘了(已经被甩了300分了还翻个P),至少后面的考试别再挂分了,把能拿的分都拿到也就是成功了。

    题解

    就一道挺傻的背包...价格很大但价值很小,于是转换一下维度,挺套路的。然后问题是询问很多,很恶心。发现其实时间的范围很小,所以应该挺容易就能想到按时间把答案预处理出来,这应该也挺套路的。至于查询的预算不一样怎么办,我们可以手动把dp数组弄成单调的,原理就是如果价值更多的方案价格反而要少,就用他去覆盖那些价值少价格高的。这也是正解的思路。但问题是如果刻意构造数据把所有物品的可购买时间都放到一天,预处理2e7的复杂度就会直接乘上300,这也是让我纠结了半天的点。最终还是没写这个,脑子一抽写了个时间复杂度是对的,但会炸内存而且实际上写错了的做法...

    放一下考场的0分代码,提醒一下自己吧。

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <map>
    using namespace std;
    inline int read() {
        int s = 0;
        char c = getchar();
        while (c < '0' || c > '9') c = getchar();
        while (c >= '0' && c <= '9') s = s * 10 + c - '0', c = getchar();
        return s;
    }
    const int maxn = 1e5 + 10;
    struct node {
        int c, val, t;
    }shop[302];
    bool cmp(node a, node b) { return a.t < b.t; }
    int n, m;
    int sum[302];
    struct DP {
        int w, id;
    }dp[302][40002];
    bool cmp2(DP a, DP b) { return a.w < b.w; }
    int main() {
        freopen("market.in", "r", stdin);
        freopen("market.out", "w", stdout);
        n = read(), m = read();
        for (int i = 1; i <= n; i++) {
    	shop[i].c = read();
    	shop[i].val = read();
    	shop[i].t = read();
    	sum[i] = sum[i - 1] + shop[i].val;
        }
        sort(shop + 1, shop + 1 + n, cmp);
        memset(dp, 0x3f, sizeof dp);
        for (int i = 0; i <= n; i++) dp[i][0].w = 0;
        for (int q = 1; q <= n; q++) {
    	for (int j = sum[q]; j >= shop[q].val; j--) {
    	    dp[q][j].id = j;
    	    dp[q][j].w = min(min(dp[q][j].w, dp[q - 1][j].w), dp[q - 1][j - shop[q].val].w + shop[q].c);
    	}
    	for (int j = shop[q].val - 1; j >= 0; j--) dp[q][j].id = j, dp[q][j].w = dp[q - 1][j].w;
        }
        for (int q = 1; q <= n; q++) {
    	sort(dp[q], dp[q] + 1 + sum[q], cmp2);
        }
        for (int i = 1; i <= n; i++) {
    	for (int j = 0; j <= sum[i]; j++) {
    	    if (j) dp[i][j].id = max(dp[i][j].id, dp[i][j - 1].id);
    	}
        }
        int T, M;
        while (m--) {
    	T = read(), M = read();
    	int l = 1, r = n, mid, id;
    	while (l <= r) {
    	    mid = (l + r) >> 1;
    	    if (shop[mid].t < T) l = mid + 1;
    	    else r = mid - 1;
    	}
    	if (l > n) l = n;
    	id = l;
    	l = 0, r = sum[id];
    	while (l <= r) {
    	    mid = (l + r) >> 1;
    	    if (dp[id][mid].w < M) l = mid + 1;
    	    else r = mid - 1;
    	}
    	//printf("l = %d r = %d
    ", l, r);
    	printf("%d
    ", dp[id][l].id);
        }
        return 0;
    }
    

    AC代码:

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    using namespace std;
    const int maxn = 305;
    struct node {
        int c, v;
    };
    int n, m;
    int dp[305][90001];
    vector<node> tim[305];
    int main() {
        //freopen("market.in", "r", stdin);
        //freopen("market.out", "w", stdout);
        scanf("%d %d", &n, &m);
        int c, v, t;
        for (int i = 1; i <= n; i++) {
    	scanf("%d %d %d", &c, &v, &t);
    	tim[t].push_back((node) { c, v });
        }
        memset(dp, 0x3f, sizeof dp);
        dp[0][0] = 0;
        for (int t = 1; t <= 300; t++) {
    	for (int i = 0; i <= n * 300; i++) dp[t][i] = dp[t - 1][i];
    	for (int i = 0; i < tim[t].size(); i++) {
    	    int c = tim[t][i].c, v = tim[t][i].v;
    	    for (int j = n * 300; j >= v; j--) dp[t][j] = min(dp[t][j], dp[t][j - v] + c);
    	}
    	for (int i = n * 300 - 1; i >= 0; i--) dp[t][i] = min(dp[t][i], dp[t][i + 1]); //如果i更大,而所需价格更少
        }
        int T, M;
        while (m--) {
    	scanf("%d %d", &T, &M);
    	int l = 0, r = n * 300, mid;
    	while (l <= r) {
    	    mid = (l + r) >> 1;
    	    if (dp[T][mid] <= M) l = mid + 1;
    	    else r = mid - 1;
    	}
    	//for (int i = 1; i <= 20; i++) printf("dp[%d][%d] = %d
    ", T, i, dp[T][i]);
    	printf("%d
    ", l - 1);
        }
    }
    
  • 相关阅读:
    [转]vc中socket编程步骤
    [转载]使用命名管道实现进程间通信
    换肤软件摘要
    3D 专业词汇 (转)
    如何从 Microsoft DirectShow 筛选器图形获取数据(转)
    “人大艺术学院”“赵雅芝中文网”等网站被挂马 狼人:
    微软将发布5月安全漏洞补丁 修补PPT 狼人:
    专家提醒:网络挂马借“海运女”传播 狼人:
    黑客借“甲型流感”传毒 挂马疾病预防控制中心网站 狼人:
    黑客称攻破乔布斯亚马逊网站账户 欲售相关信息 狼人:
  • 原文地址:https://www.cnblogs.com/Zfio/p/13767678.html
Copyright © 2011-2022 走看看