为防止广告,目前nocow只有登录用户能够创建新页面。如要创建页面请先登录/注册(新用户需要等待1个小时才能正常使用该功能)。

URAL/1223

来自NOCOW
跳转到: 导航, 搜索

哎哎,一道比较好的DP题吧~ 来贴个C++的题解。。。

膜拜朱晨光大牛~Orz。。。

#include <iostream>
#include <cmath>
using namespace std;
int EggNum,N,g[21];
inline void DP()
{
    for (int i=2;i<=N;i++)
    {
        for (int j=EggNum;j>1;j--)
        {
            g[j]+=g[j-1]+1;
            if ((j == EggNum) && (g[j] >= N))
            {
                cout << i << endl;
                return;
            }
        }
        g[1]=i;
    }
}
int main(void)
{
    while (true)
    {
        cin >> EggNum;
        if (!EggNum)  break;
        cin >> N;
        int tmp=(int)(floor(log((double)N)/log(2.0))+1.0);
        if (EggNum >= tmp)
            cout << tmp << endl;
        else
        {
            for (int i=1;i<=EggNum;i++)
                g[i]=1;
            if (g[EggNum] >= N)
                cout << '1' << endl;
            else if (EggNum == 1)
                cout << N << endl;
            else DP();
        }
    }
    return 0;
}
//by zzy

究级算法,不管是空间还是时间都是理论上最优的,可以证明复杂度为O(sqrt(n))

program cyd;
  var
    g:array[0..1,0..1000]of longint;
    i,n,m,x,k:longint;
  begin
    readln(n,m);
    while (n<>0)and(m<>0) do
      begin
        for i:=1 to n do
          g[0,i]:=1;
        x:=1; k:=0;
        while g[k,n]<m do
          begin
            inc(x); k:=1-k;
            for i:=1 to n do
              g[k,i]:=g[1-k,i-1]+g[1-k,i]+1;
          end;
        writeln(x);
        readln(n,m);
      end;
  end.

因为对空间进行了优化,所以可能不他爱好理解,具体的应为:g[i,j]:=g[i-1,j-1]+g[i-1,j]+1;

g[i,j]表示的是用j个鸡蛋试i次能达到的最大楼层,目的就是找到一个g[i-1,j]<m 且 g[i,j]>=m i就是答案。

转移方程,由目的看出,如果g[i-1,j]<m 那么对于g[i-1,j]的情况肯定能出解,那么我们必然会直接试>g[i-1,j]层,用j-1个鸡蛋试最大高度,再用最后一个鸡蛋优

化答案。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int f[15][1101]; //f[i][j]表示用i个蛋试第j层楼的最坏结果
int n,m;
int min(int a,int b)
{
	if (a<b) return a;else return b;
}
int max(int a,int b)
{
	if (a>b) return a;else return b;
}
int main()
{
	for (int i=1;i<=1000;i++)
	{
		f[1][i]=i;
		f[0][i]=0;
	}
	for (int i=1;i<=11;i++)
	{
		f[i][0]=0;
		f[i][1]=1;
	}
	for (int i=2;i<1001;i++) //枚举楼层
	{
		for (int j=2;j<11;j++) //枚举蛋数
		{
			int minn=0x3FFFFFFF;
			for (int k=1;k<=i;k++) //k表示第k层楼
			{
				minn=min(minn,max(f[j-1][k-1],f[j][i-k]));
                                //假如在第K-1层楼碎就用剩下j-1个蛋去试剩下的,如果在第k层都不碎就用就个蛋试上面的i-k层楼
			}
			f[j][i]=minn+1;
		}
	}
	while (scanf("%d%d",&n,&m)!=EOF)
	{
		if (n==0 && m==0) break;
		if (n>10) printf("%d\n",f[10][m]);
		else printf("%d\n",f[n][m]);
	}
}
//by Exia
个人工具