状态A
状态:d[i][j] 已经第i首歌还剩j时间,还能最多唱几首
决策:唱或不唱 1)d[i][j]-->d[i+1][j-song[i]] ;2)d[i][j]-->d[i+1][j] ;
选择:最大的但j>0的
int dp(int i,int j)
{
int& ans=d[i][j];
if(d[i][j]>=0) return ans;
ans=-1;
if(i==n) ans=0;
else
{
if(j>song[i]) ans=dp(i+1,j-song[i])+1;
ans=max(ans,dp(i+1,j));
}
return ans;
}
int main()
{
int T,kase=0;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&t);
for(int i=0;i<n;i++)
scanf("%d",&song[i]);
memset(d,-1,sizeof(d));
int ans=dp(0,t);
int ans_t;
for(int j=1;j<=t;j++) if(d[n][j]!=-1) { //能走到n点的且t为最小的
ans_t=j;break;
}
printf("Case %d: %d %d\n",++kase,ans+1,t-ans_t+Jin);
}
return 0;
}
2)递推法
int main()
{
int T,kase=0;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&t);
for(int i=0;i<n;i++)
scanf("%d",&song[i]);
memset(d,-1,sizeof(d));
int ans_t;
for(int i=n;i>=0;i--)
for(int j=0;j<=t;j++)
{
int& ans=d[i][j];
if(i==n) ans=0;
else
{
ans=-1;
if(j>song[i]) ans=d[i+1][j-song[i]]+1;
ans=max(ans,d[i+1][j]);
}
}
// for(int i=n;i>=0;i--) //测试输出d[i][j]的值
// {
// for(int j=0;j<=t;j++)
// cout<<d[i][j]<<' ';
// cout<<endl;
// }
printf("Case %d: %d %d\n",++kase,a[0][t]+1,t-ans_t+Jin);
}
//难打印时间,因为d[0][60~100]都为1;
return 0;
}
状态B
状态:d[i][j] 已经第i首歌用时j时间,还能最多唱几首
决策:唱或不唱 1)d[i][j]-->d[i+1][j+song[i]] ;
2)d[i][j]-->d[i+1][j] ;
选择:最大的但j<t的
int dp(int i,int j)
{
int& ans=d[i][j];
if(d[i][j]>=0) return ans;
ans=-1;
if(i==n) ans=0;
else
{
if(j+song[i]<t) ans=dp(i+1,j+song[i])+1;
ans=max(ans,dp(i+1,j));
}
return ans;
}
int main()
{
int T,kase=0;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&t);
for(int i=0;i<n;i++)
scanf("%d",&song[i]);
memset(d,-1,sizeof(d));
int ans=dp(0,0);
int ans_t;
for(int j=t-1;j>=0;j--) if(d[n][j]!=-1) {
ans_t=j;break;
}
printf("Case %d: %d %d\n",++kase,ans+1,ans_t+Jin);
}
return 0;
}
2)递推法
int main()
{
int T,kase=0;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&t);
for(int i=0;i<n;i++)
scanf("%d",&song[i]);
memset(d,-1,sizeof(d));
int ans_t;
for(int i=n;i>=0;i--)
for(int j=0;j<=t;j++)
{
int& ans=d[i][j];
if(i==n) ans=0;
else
{
ans=-1;
if(j+song[i]<t) ans=d[i+1][j+song[i]]+1;
ans=max(ans,d[i+1][j]);
}
}
// for(int i=n;i>=0;i--)
// {
// for(int j=0;j<=t;j++)
// cout<<d[i][j]<<' ';
// cout<<endl;
// }
//难打印时间,因为d[0][0~40]都为1;
// printf("Case %d: %d %d\n",++kase,ans+1,ans_t+Jin);
}
return 0;
}
状态C
状态:d[i][j] 从第i首歌起,用了j时间,最多能唱几首
决策:唱或不唱 1)d[i][j]-->d[i+1][j+song[i]] ;
2)d[i][j]-->d[i+1][j] ;
选择:最大的但j<t的
1)记忆化搜索
int dp(int i,int j)
{
int& ans=d[i][j];
if(d[i][j]>=0) return ans;
ans=-1;
if(i==n+1) ans=0;
else
{
if(j+song[i]<t) ans=dp(i+1,j+song[i])+1;
ans=max(ans,dp(i+1,j));
}
return ans;
}
int main()
{
int T,kase=0;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&t);
for(int i=1;i<=n;i++)
scanf("%d",&song[i]);
memset(d,-1,sizeof(d));
int ans=dp(1,0),ans_t;
for(int i=t-1;i>=0;i--)
if(d[n+1][i]!=-1) {
ans_t=i;
break;
}
printf("Case %d: %d %d\n",++kase,ans+1,ans_t+Jin);
}
return 0;
}
2)递推法
int main()
{
int T,kase=0;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&t);
for(int i=1;i<=n;i++)
scanf("%d",&song[i]);
memset(d,-1,sizeof(d));
for(int i=n+1;i>=0;i--)
for(int j=0;j<=t;j++)
{
int& ans=d[i][j];
if(i==n+1) ans=0;
else
{
ans=-1;
if(j+song[i]<t) ans=d[i+1][j+song[i]]+1;
ans=max(ans,d[i+1][j]);
}
}
// for(int i=n;i>=1;i--)
// {
// for(int j=0;j<=t;j++)
// cout<<d[i][j]<<' ';
// cout<<endl;
// }
// printf("Case %d: %d %d\n",++kase,ans+1,ans_t+Jin);
}
return 0;
}
状态:d[i][j] 从第i首歌起,j时间内,最多能唱几首
决策:唱或不唱 1)d[i][j]-->d[i+1][j-song[i]] ;
2)d[i][j]-->d[i+1][j] ;
选择:最大的但j>0的
1)记忆化搜索
int dp(int i,int j)
{
int& ans=d[i][j];
if(d[i][j]>=0) return ans;
ans=-1;
if(i==n+1) ans=0;
else
{
if(j-song[i]>0) ans=dp(i+1,j-song[i])+1;
ans=max(ans,dp(i+1,j));
}
return ans;
}
int main()
{
int T,kase=0;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&t);
for(int i=1;i<=n;i++)
scanf("%d",&song[i]);
memset(d,-1,sizeof(d));
int ans=dp(1,t),ans_t;
for(int i=0;i<t;i++)
if(d[n+1][i]!=-1) {
ans_t=i;
break;
}
printf("Case %d: %d %d\n",++kase,ans+1,t-ans_t+Jin);
}
return 0;
}
2)递推法
int main()
{
int T,kase=0;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&t);
for(int i=1;i<=n;i++)
scanf("%d",&song[i]);
memset(d,-1,sizeof(d));
for(int i=n+1;i>=0;i--)
for(int j=0;j<=t;j++)
{
int& ans=d[i][j];
if(i==n+1) ans=0;
else
{
ans=-1;
if(j-song[i]>0) ans=d[i+1][j-song[i]]+1;
ans=max(ans,d[i+1][j]);
}
}
// for(int i=n;i>=1;i--)
// {
// for(int j=0;j<=t;j++)
// cout<<d[i][j]<<' ';
// cout<<endl;
// }
// printf("Case %d: %d %d\n",++kase,ans+1,ans_t+Jin);
}
return 0;
}
下面是相反的定义,从1到n
状态:d{i][j] 前i首歌,用时j最多唱了几首
状态转移:1) d[i][j]-->d[i-1][i-song[i]]+1
2) d[i][j]-->d[i-1][j];
状态选择:最大的
int main()
{
int T,kase=0;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&t);
for(int i=1;i<=n;i++)
scanf("%d",&song[i]);
memset(d,-1,sizeof(d));
for(int i=0;i<=n;i++)
for(int j=0;j<=t;j++)
{
int& ans=d[i][j];
if(i==0) ans=0;
else
{
ans=-1;
if(j-song[i]>0) ans=d[i-1][j-song[i]]+1;
ans=max(ans,d[i-1][j]);
}
}
cout<<d[n][t];
// printf("Case %d: %d %d\n",++kase,ans+1,ans_t+Jin);
}
return 0;
}
但递推法的都不知道怎么求出最大用时,可能是状态定义的不好