江西财经大学第一届程序设计竞赛 G-小Q的口袋校园

本文介绍了一种通过算法解决活动选择问题的方法,旨在帮助用户在有限的时间内选择能够带来最大快乐值和绩点数的活动组合。通过01背包问题的思路,利用动态规划实现了最优解的计算。
链接: https://www.nowcoder.com/acm/contest/115/G
来源:牛客网

题目描述

周末,小Q喜欢在PU口袋校园上参加各种活动刷绩点,体验丰富多彩的大学生活。
但是每个活动有各自的开始时间、结束时间、Happy值以及绩点数,活动之间可能存在时间冲突。
小Q是一个认真踏实的女孩,她在同一时间只会参加一个活动。
给出每一天的活动数,求小Q在同一天内所能获得的最大Happy值 与 绩点数。
小Q是一个活泼开朗的女孩,她总是寻求最大的Happy值,如果Happy值相同,才会尽可能使绩点数更多。

输入描述:

第一行输入一个整数T(表示样例个数)
接下来T组样例
每组样例第一行输入一个整数N(表示有几项活动)
接下来N行,每行输入s,e,h,p 4个整数,分别代表一个活动的开始时间、结束时间、Happy值以及绩点数
0<=s<e<=24,1<=h,p<=100,1<=T,N<=20

输出描述:

输出T行
一行输出一个样例对应的结果
小Q在一天内所能获得的最大 Happy值 与 绩点数

一维数组版:无注释(下面有二维数组注释版)


#include <stdio.h>
#include <algorithm>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <iostream>
#include <vector>
using namespace std;
#define N 25
int happy[N],point[N];
struct activity {
    int s,e,h,p;
    bool friend operator <(activity a,activity b) {
        return a.s < b.s;
    }
}ac[105];

int main(){
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
        int t;
        cin>>t;
        while(t--){
            int n;
            cin>>n;
            for(int i=0;i<n;i++) cin>>ac[i].s>>ac[i].e>>ac[i].h>>ac[i].p;
            sort(ac,ac+n);
            memset(happy,0,sizeof(happy));
            memset(point,0,sizeof(point));
            for(int i=0;i<n;i++) {
                for(int j=ac[i].e;j<=24;j++) {
                    if(happy[j] < happy[ac[i].s] + ac[i].h) {
                        happy[j] = happy[ac[i].s] + ac[i].h;
                        point[j] = point[ac[i].s] + ac[i].p;
                    }else if(happy[j] == happy[ac[i].s] + ac[i].h) point[j] = max(point[j],point[ac[i].s]+ac[i].p);
                }
            }
            cout<<happy[24]<<" "<<point[24]<<endl;
        }
       return 0;
}

/*题型:01背包*/
/*思路:使用二维数组来记录选择与否所能达到的最优状态*/
/*动态转移方程:m=hp[i-1][v[i].s]+v[i].h,n=hp[i-1][c]);hp[i][c]=max(m,n);*/
/*				x=sc[i-1][v[i].s]+v[i].p,y=sc[i-1][c];*/
/*				if(m>n) sc[i][c]=x;*/
/*				if(m==n) sc[i][c]=max(x,y);*/
/*				if(m<n) sc[i][c]=y;*/
/*解释-关于hp: 若是选择当前i活动,那么前(i-1)件活动的底线时间是v[i].s,获得的hp是在此底线时间下的hp最大值加上当前的hp值*/
/*	happiness	若是不选择,那么前i-1件活动就拥有了现在的未经占用的底线时间,获得的hp是在此底线时间下的最大值*/
/*解释-关于sc:	若是选择第i活动(m>n),获得的sc是之前i-1件活动在底线时间为v[i].s条件下获得的sc值加第i个活动的sc值*/
/*		score	这并不一定是sc的最佳值*/
/*				若是获得的hp相等(m==n),这时就要通过选或不选来使能获得的sc利益最大化了*/
/*				若是不选择第i活动(m<n),获得的sc是之前i-1件活动在当前底线时间条件下能获得的sc值*/ 
/*Ps:一定注意若是选择,之前i-1件活动拥有的底线时间是固定的(=v[i].s),而不是现有时间-当前活动时长				*/
/*Ps.2: 关于绩点sc,hp相等时一定要判断哪种情况获得的sc更大;而不是在m!>n之后简单的赋值为sc[i][c]]*/ 
#include<bits/stdc++.h>
using namespace std;
struct info{
	int s,e,h,p;
	//start end happy point
	bool friend operator <(info a,info b)
	{
		return a.e<b.e;
	}
};
vector<info> v;
int hp[25][25];
int sc[25][25];
int main()
{
	int T,N;
	int i,j;
	int m,n;
	cin>>T;
	while(T--)
	{
		v.clear();
		memset(hp,0,sizeof(hp));
		memset(sc,0,sizeof(sc));
		cin>>N;
		for(i=0;i<N;i++)
		{
			info x;
			cin>>x.s>>x.e>>x.h>>x.p;
			v.push_back(x);
		}
		sort(v.begin(),v.end());
		for(i=24;i>=v[0].e;i--)
		{
			hp[0][i]=v[0].h;
			sc[0][i]=v[0].p;
		}
		for(i=1;i<N;i++)
			for(j=24;j>=0;j--)
			{
				n=hp[i-1][j];
				
				if(j>=v[i].e)
				{
					m=hp[i-1][v[i].s]+v[i].h;
					hp[i][j]=max(m,n);
					if(m>n) sc[i][j]=sc[i-1][v[i].s]+v[i].p;
					else if(m==n) sc[i][j]=max(sc[i-1][j],sc[i-1][v[i].s]+v[i].p);
					else sc[i][j]=sc[i-1][j];
				}
				else
				{
					hp[i][j]=n;
					sc[i][j]=sc[i-1][j];
				}
				
			}
		cout<<hp[N-1][24]<<" "<<sc[N-1][24]<<endl;
	}
    return 0;
}


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值