真的是好久没有做题了,一点手感都没有,思想也变迟钝了,两战在即,应该慢慢拾回最佳状态了。
题意:有m门课,每门课有最少花费时间,最多花费时间,难度系数。从这m门课中选出n门,要求每门课所花时间在要求的范围内,且难度是绝对递增的,同时当前一门课所花时间比前一门课所花时间多k或者是它的k倍。问是否可能,YES/NO,若可能的话,输出总时间最多的那种情况(1<=n<=m<=50,1<=k<=100,1<=a,b<10^16且b-a<=100).
思路:因为a,b范围太大,不能直接保存。但b-a<=100,所以可以开二维表示某门课所要花的时间。最终一定要做n门课,所以再加一维表示当前课程是第几门要做的,dp[i][j][k]表示当前的课程j是选中的第i门课,所花的时间比j的最少时间多k。可以由dp[i-1]推导dp[i],同时又要总时间最多,所以加一个sum[i][j][k]表示第i门课选j的最多的总时间,然后选取最优的情况即可。
犯的错误:刚开始没有认真看a,b的范围,RE
接下来以为总时间最多的情况就是存在比此时时间少k的先选,后选是k倍的(k=1时还要单独考虑一下)。但这只保证了前面一个是最大的,但不能保证前面的和是最大的。在这WA了N久。
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
struct point//课程信息
{
__int64 n,a,b,c;//下标,最少时间,最多时间,难度系数
}p[110];
struct po
{
__int64 a,b;//上一门课是a,所花时间是p[a].a+b
}pre[51][51][110];
bool cmp(point a,point b)//课程按难度系数排序
{
if(a.c!=b.c)
return a.c<b.c;
if(a.b!=b.b)
return a.b>b.b;
return a.a>b.b;
}
__int64 dp[51][51][110];//dp[i][j][k]表示选的第i门课为j,做p[j].a+k时间
__int64 sum[51][51][110];//选的第i门课为j,做p[j].a+k久的总时间
void DFS(__int64 n,__int64 i,__int64 j)
{
if(n<=1)
{
printf("%I64d %I64d\n",p[i].n,p[i].a+j);
return;
}
DFS(n-1,pre[n][i][j].a,pre[n][i][j].b);
printf("%I64d %I64d\n",p[i].n,p[i].a+j);
}
int main()
{
__int64 n,m,k,i,j,kk,ii,j1,a,b,c;
while(scanf("%I64d%I64d%I64d",&n,&m,&k)!=EOF)
{
for(i=0;i<m;i++)
{
scanf("%I64d%I64d%I64d",&p[i].a,&p[i].b,&p[i].c);
p[i].n=i+1;
}
memset(dp,0,sizeof(dp));
memset(sum,0,sizeof(sum));
sort(p,p+m,cmp);//按难易排序
for(kk=1;kk<=n;kk++)
for(i=0;i<m;i++)
{
for(j=0;j<=p[i].b-p[i].a;j++)
{
if(kk==1)
{
dp[kk][i][j]=p[i].c;
sum[kk][i][j]=p[i].a+j;
continue;
}
for(a=0,b=0,c=0,ii=0;ii<i;ii++)//如果上一门课选ii
{
if(p[ii].c==p[i].c) break;
if(p[i].a+j-k>=p[ii].a&&p[i].a+j-k<=p[ii].b&&dp[kk-1][ii][p[i].a+j-k-p[ii].a])//比上一门课多k
{
j1=p[i].a+j-k-p[ii].a;
if(sum[kk-1][ii][j1]>c)
a=ii,b=j1,c=sum[kk-1][ii][j1];
}
if((p[i].a+j)%k==0&&(p[i].a+j)/k>=p[ii].a&&(p[i].a+j)/k<=p[ii].b&&dp[kk-1][ii][(p[i].a+j)/k-p[ii].a])//是上一门课的k倍
{
j1=(p[i].a+j)/k-p[ii].a;
if(sum[kk-1][ii][j1]>c)
a=ii,b=j1,c=sum[kk-1][ii][j1];
}
if(c)//如果可以
{
dp[kk][i][j]=p[i].c;
pre[kk][i][j].a=a;
pre[kk][i][j].b=b;
sum[kk][i][j]=c+p[i].a+j;
}
}
}
}
for(a=0,b=0,c=0,i=0;i<m;i++)//找总时间最多的
for(j=0;p[i].a+j<=p[i].b;j++)
if(dp[n][i][j])
{
if(sum[n][i][j]>c)
a=i,b=j,c=sum[n][i][j];
}
if(!c)
{
printf("NO\n");
continue;
}
printf("YES\n");
DFS(n,a,b);//深搜输出
}
return 0;
}