Codeforces Beta Round #90 C. Education Reform

本文介绍了一种使用动态规划解决课程选择问题的方法,通过三维DP数组跟踪最优解路径,确保所选课程符合作业量和难度的要求。文章详细解释了状态定义、转移方程及输出解的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先把课程按照难度排序。

dp[i][j][k]表示已经选了i门课,最后选出的一门课是排序后的第j个,最后一门课安排的作业量是k+p[j].a的时候最多的作业量和是多少。转移的时候枚举下一门选择的课程,判断下K*(p[j].a+k),K+(p[j].a+k)和下一门课程作业的范围之间的关系就可以了,dp时维护路径,输出解。注意不要用非法状态去转移。

#include <bits/stdc++.h>
using namespace std;
__int64 dp[51][51][109];
int X[51][51][109],Y[51][51][109];
struct node
{
	__int64 a,b;
	int c,id;
	bool operator<(const node &rhs)const
	{
		return c<rhs.c;
	}
}p[55];
int n,m,K;
void output(int dep,int x,int y)
{
	if(dep==0)
		return ;
	output(dep-1,X[dep][x][y],Y[dep][x][y]);
	printf("%d %I64d\n",p[x].id,p[x].a+y);
}
int main()
{
	scanf("%d%d%d",&n,&m,&K);
	for(int i=1;i<=m;i++)
	{
		scanf("%I64d%I64d%d",&p[i].a,&p[i].b,&p[i].c);
		p[i].id=i;
	}
	sort(p+1,p+1+m);
	for(int i=1;i<=m;i++)
	{
		for(int j=0;j<=p[i].b-p[i].a;j++)
		{
			dp[1][i][j]=p[i].a+j;
		}
	}
	for(int i=1;i<n;i++)
	{
		for(int j=i;j<=m;j++)
		{
			for(int k=0;k<=p[j].b-p[j].a;k++)
			{
				__int64 cur=p[j].a+k;
				if(dp[i][j][k]==0)
					continue;               //非法状态
				for(int x=j+1;x<=m;x++)
				{
					if(p[x].c==p[j].c)
						continue;
					if(p[x].a<=cur+K&&cur+K<=p[x].b)
					{
						if(dp[i+1][x][cur+K-p[x].a]<dp[i][j][k]+K+cur)
						{
							dp[i+1][x][cur+K-p[x].a]=dp[i][j][k]+K+cur;
							X[i+1][x][cur+K-p[x].a]=j;
							Y[i+1][x][cur+K-p[x].a]=k;
						}
					}
					if(p[x].a<=cur*K&&cur*K<=p[x].b)
					{
						if(dp[i+1][x][cur*K-p[x].a]<dp[i][j][k]+K*cur)
						{
							dp[i+1][x][cur*K-p[x].a]=dp[i][j][k]+K*cur;
							X[i+1][x][cur*K-p[x].a]=j;
							Y[i+1][x][cur*K-p[x].a]=k;
						}
					}
				}
			}
		}
	}
	__int64 ans=0;
	int x,y;
	for(int i=1;i<=m;i++)
		for(int j=0;j<=100;j++)
		{
			if(ans<dp[n][i][j])
			{
				ans=dp[n][i][j];
				x=i;y=j;
			}
		}
	if(ans==0)
	{
		printf("NO\n");
	}
	else
	{
		printf("YES\n");
		output(n,x,y);
	}
	//system("pause");
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值