51nod 2542 咖啡和作业

2542 咖啡和作业

你要完成一个mm页的作业,手里有nn杯咖啡,每一杯咖啡有一个咖啡因强度值aiai,能支撑你写aiai页作业。每一天你会选择一些咖啡喝掉,对于当天喝的第i杯咖啡,咖啡因的强度会减弱i−1i−1单位,减到00就不再减小。问你最少经过几天能完成作业。

输入
第一行两个正整数n,m。
第二行n个数表示a[1…n]。
n<=100,m<=10000,1<=a[i]<=100。

输出
如果无解,输出-1;
否则输出最少天数。

输入样例
5 8
2 3 1 1 2

输出样例
4

题解:动态规划我们要考虑 状态的表示 和 状态转移方程,对于本题很显然我们可以用二维数组来表示
f[i][j]表示第i天喝第j杯咖啡能得到的最大咖啡因。转移方程也很显而易见,就是前一天的上一杯和今天的上一杯转移过来,因为前一天上一杯的状态转移过来可能会小于今天上一杯的咖啡因,所以我们需要临时储存下前一天转移来的状态。

#include
#include

using namespace std;

const int N = 110;

int f[N][N], a[N],vis[N][N];

int n, m, ans = 1e6;

bool cmp(int x, int y)
{
	return x > y;
}

int main()
{
	cin >> n >> m;
	int sns = 0;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		sns += a[i];
	}
	sort(a + 1, a + n + 1, cmp);
	if (sns < m)
	{
		cout << -1 << endl;
		return 0;
	}
	else
	{
		f[1][1]=a[1];
		vis[1][1]=1;
		int s=f[1][1];
		for(int j=2;j<=n;j++)
		{
			if(a[j] > vis[1][j-1])
//				f[1][j] = f[1][j-1] - vis[1][j-1] + a[j];
				s = s - vis[1][j-1] + a[j];
//			else
//				f[1][j]=f[1][j-1];
			
			f[1][j]=max(s,f[1][j]);
			vis[1][j]=vis[1][j-1] + 1;
			
			if(f[1][j]>=m)
				ans=min(ans,1);
		}
		
		for (int i = 2; i <= n; i++)
		{
			for (int k = i; k <= n; k++)
			{
				
//				f[i][k] = f[i-1][k-1] + a[k];
				s = f[i-1][k-1] + a[k];
				f[i][k]=max(f[i][k],s);
				vis[i][k] = 1;
			
				if(f[i][k]>=m)
					ans=min(ans,i);
					
				for(int j= k + 1;j <= n;j++)
				{
					if(a[j] > vis[i][j-1])
						s = s - vis[i][j-1] + a[j];
//						f[i][j] = f[i][j-1]-vis[i][j-1] + a[j];
//					else
//						f[i][j]=f[i][j-1];
					f[i][j] = max(s,f[i][j]);
					vis[i][j]=vis[i][j-1] + 1;
					if(f[i][j]>=m)
						ans=min(ans,i);
				}
				
			}
		}
	}
//	3 2 2 1 1
//	for(int i=1;i<=n;i++)
//	{
//		for(int k=1;k<=n;k++)
//			cout<

你可能感兴趣的:(51nod)