7-11 种苹果 (30分)(未完成不AC)

7-11 种苹果 (30分)

最近流行种苹果的游戏,玩家种下一颗苹果树,初始成长值为0,每次浇水都会增加成长值,当成长值大于等于V时,就可以收获成熟的苹果了。玩家拥有五种颜色(红色、黄色、蓝色、绿色、紫色)的水壶若干个,每浇水一次就消耗一个水壶,不同颜色的水壶水量不一定一样,因此用不同颜色的水壶浇水苹果树获得的成长值也可能不一样。苹果成熟后剩余水壶中的水量仍然可以继续在下一局游戏中继续使用,因此,玩家想用最少的水量让苹果成熟,最大程度节约水量。请你帮他计算下苹果成熟的最少浇水量。

输入格式:

输入第一行为一个整数T(1<=T<=100),代表测试数据的组数,每组数据的第一行为一个整数V(0<=V<=1012),代表苹果成熟应达到的成长值,随后5行,每行包括三个整数N,G,W(0<=N<=1000,0<=W,G<=109),分别代表其中一种颜色水壶的个数,浇水后对应的成长值,水量,中间用空格分割,并且所有颜色水壶的总个数不超过1000。

输出格式:

每组数据都对应一行输出。如果苹果能够成熟,该行输出两个整数,分别代表苹果成熟时的最低浇水量和所获得的成长值。如果所有水壶的水量都浇上,苹果也成熟不了,则输出”Impossible!”。

输入样例:

3
100
20 5 5
16 10 4
3 20 10
15 2 2
5 8 6
60
2 3 2
3 5 6
1 3 5
2 6 1
3 4 2
50
2 20 10
3 10 20
2 5 6
20 4 10
12 6 5

输出样例:

40 100
Impossible!
30 52

只能通过第一个测试点的代码:(等待大佬的AC代码)

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
struct wpot{
	int N;
	long long G,W;
	float perwater;
};
bool cmp(struct wpot pot1,struct wpot pot2){
	if(pot1.perwater != pot2.perwater)
	return pot1.perwater > pot2.perwater;
	else
	return pot1.N*pot1.G > pot2.N*pot2.G;
}
int main(){
	int T;
	cin >> T;
	while(T--){
		long long num;
		cin >> num;
		struct wpot pot[7];
		long long sum = 0;
		for(int i = 0;i < 5;i++){
			cin >> pot[i].N >> pot[i].G >> pot[i].W;
			pot[i].perwater = 1.0*pot[i].G / pot[i].W; 
			sum += pot[i].N * pot[i].G;
		}
		sort(pot,pot+5,cmp);
		if(sum < num){
			cout << "Impossible!" << endl;
		}else{
			long long water = 0,grow = 0;
			for(int i = 0;i < 5;i++){
				if(pot[i].N*pot[i].G >= num){
					long long bei = (int)(1.0*num/pot[i].G+0.999999);
					water += bei * pot[i].W;
					grow += bei * pot[i].G;
					break;
				}else{
					water += pot[i].N * pot[i].W;
					grow += pot[i].N * pot[i].G;
					num -= grow;
				}
			}
			cout << water << " " << grow << endl;
		}
	}
}

大佬写出来的AC代码,及思想,借鉴一下:

/*
刘哲轩
经典的多重背包问题,但是由于体积太大,不好使用动态规划,所以改用dfs+贪心剪枝。
这题采用7-8月饼类似的贪心方法可以拿到20分,但是这种做法是错误的,比如
1
100
3 30 10
2 20 9
5 11 5
5 7 7
5 8 8

由于30/10=3>20/9=2.222>11/5=2.2,所以采用贪心算法会选择三个第一种壶和一个第二种水壶总用水量是39,但是选择三个第一种壶和一个第三种壶用水量是35,显然更优,因此单纯的贪心算法是错误的。
但是这题dfs+二分的时间复杂度是O(n^4*logn),会超时。但是由于最优解一定在贪心算法所求的可行解的答案附近,所以可以dfs搜索贪心算法所求出的解的邻域。
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct my {
    ll w, g;
    int num;
    double g_w;
    bool operator<(const my& t) { return g_w > t.g_w; }
}tr[5];
ll ans = 1e18, sum, res = 0, sres = 0;
double n[5];
void dfs(ll V, int u) {
    if (V <= 0) {
        if (ans > res) {
            ans = res;
            sum = sres;
        }
        return;
    }
    if (u == 4) {
        ll t = min((ll)tr[u].num, V / tr[u].g + 1);
        if (t * tr[u].g >= V) {
            if (ans > res + t * tr[u].w) {
                ans = res + t * tr[u].w;
                sum = sres + t * tr[u].g;
            }
        }
        return;
    }
    if (V % tr[u].g == 0 && V / tr[u].g <= tr[u].num) {
        if (ans > res + V / tr[u].g * tr[u].w) {
            ans = res + V / tr[u].g * tr[u].w;
            sum = sres + V;
        }
    }
    else {
        ll up = min((ll)tr[u].num, (ll)n[u] + 9), down = max(0ll, (ll)n[u] - 9);
        for (int i = down; i <= up; i++) {
            res += i * tr[u].w;
            sres += i * tr[u].g;
            dfs(V - i * tr[u].g, u + 1);
            res -= i * tr[u].w;
            sres -= i * tr[u].g;
        }
    }
}
void solve() {
    ans = 1e18, sum = 0, res = 0, sres = 0;
    ll Vt,V;
    scanf("%lld", &V);
    Vt = V;
    for(int i=0;i<5;i++) n[i]=0;
    for (int i = 0; i < 5; i++) { scanf("%d %lld %lld", &tr[i].num, &tr[i].g, &tr[i].w); tr[i].g_w = (double)tr[i].g / tr[i].w; }
    sort(tr, tr + 5);
    for (int i = 0; i < 5; i++) {
        if (!V) break;
        if (tr[i].g * tr[i].num >= V) 
        {        n[i] = (double)V / tr[i].g;
        V = 0;
        }
        else V -= tr[i].g * tr[i].num, n[i] = tr[i].num;
    }
    dfs(Vt, 0);
    if (ans == 1e18) puts("Impossible!");
    else printf("%lld %lld\n", ans, sum);
}
int main() {
    int Case;
    cin >> Case;
    while (Case--) solve();
    return 0;
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

China-Rookie-LSJ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值