Raucous Rockers

题意:有N首歌(按照写作的顺序给出每首歌的时间),还有M个压缩碟,每个压缩碟能容纳T分钟的歌曲。歌曲不允许跨碟存储,而且要按照写作顺序存储。求这M个压缩碟最多可以存储多少首歌?

解题思路

  1. DP问题,开始不知到怎么做,于是参考了USACO中Skywalker的“一种时间复杂度O(n^2)的DP算法”(http://www.nocow.cn/index.php/USACO/rockers
  2. f(i, j) = (a, b)代表在最优情况下,从前i首歌曲中存储j首歌曲后,已经占用a个压缩碟,且第a+1个压缩碟中已经占据b时间
  3. 边界条件j=0时,f(i, j) = (0, 0)
  4. 滚雪球的过程:f(i, j) = min(f(i - 1, j), f(i - 1, j - 1) + cost_of_song(i))。也就是将f(i, j)分为不包括第i首歌以及包括第i首歌两种情况。求最小值要比较(a, b)这个数对,首先比较a,在a相等的情况下再比较b
  5. 最后从N到0遍历f[N][j],找到第一个满足条件的数对(a, b)那么对应的j就是最终的答案

代码

/*
ID: zc.rene1
LANG: C
PROG: rockers
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define MAX 20

int main(void)
{
    FILE *fin, *fout;
    int N, T, M;
    int songs[MAX + 1];
    int f[MAX + 1][MAX + 1][2];
    int i, j, temp_m, temp_t;

    fin = fopen("rockers.in", "r");
    fout = fopen("rockers.out", "w");
    /*get the input*/
    fscanf(fin, "%d %d %d", &N, &T, &M);
    for (i=1; i<=N; i++)
    {
	fscanf(fin, "%d", &songs[i]);
    }
    /*begin DP*/
    for (i=0; i<=N; i++)
    {
	for (j=0; j<=N; j++)
	{
	    if (j == 0)
	    {
		memset(f[i][j], 0, 2 * sizeof(int));
	    }
	    else
	    {
		f[i][j][0] = M;
		f[i][j][1] = T;
	    }
	}
    }

    for (i=1; i<=N; i++)
    {
	for (j=1; j<=i; j++)
	{
	    temp_m = f[i-1][j-1][0];
	    temp_t = f[i-1][j-1][1];

	    if (songs[i] > T)
	    {
		temp_m = M;
		temp_t = T;
	    }
	    else
	    {
		if ((temp_t + songs[i]) <= T)
		{
		    temp_t += songs[i];
		}
		else
		{
		    temp_m++;
		    temp_t = songs[i];
		}
	    }

	    if (f[i-1][j][0] < temp_m)
	    {
		memcpy(f[i][j], f[i-1][j], 2 * sizeof(int));
	    }
	    else if (f[i-1][j][0] == temp_m)
	    {
		if (f[i-1][j][1] > temp_t)
		{
		    f[i][j][0] = temp_m;
		    f[i][j][1] = temp_t;
		}
		else
		{
		    memcpy(f[i][j], f[i-1][j], 2 * sizeof(int));
		}
	    }
	    else
	    {
		f[i][j][0] = temp_m;
		f[i][j][1] = temp_t;
	    }
	}
    }
	    
    for (j=N; j>=0; j--)
    {
	if (f[N][j][0] < M)
	{
	    fprintf(fout, "%d\n", j);
	    break;
	}
    }

    if (j == -1)
    {
	fprintf(fout, "0\n");
    }

    
    return 0;
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值