wiki-1260-快餐问题

这道题绝对在我做过的题中排最恶心之首。(以下是网上找的解析,程序是自己写的c++)

本题是一个非常典型的资源分配问题。由于每条生产线的生产是相互独立,不互相影响的,所以此题可以以生产线为阶段用动态规划求解。 状态表示: 用p[I,j,k]表示前I 条生产线生产j 个汉堡,k 个薯条的情况下最多可生产饮料的个数。用r[I,j,k]表示第I 条生产线生产j 个汉堡,k 个薯条的情况下最多可生产饮料的个数。 态转移方程: 
 p[I,j,k] = Max{p[I-1,j1,k1]+r[I,j-j1,k-k1]} 
(0<=j1<=j,0<=k1<=k,且(j-j1)*p1+(k-k1)*p2<= 第I 条生产线的生产时间)但这样的算法是非常粗糙的,稍加分析可以发现,此算法的时间复杂度为O(N*1004),当N=10 的时候,时间复杂度将达到10*1004=109,这是根本无法承受的。于是,我们必须对算法进行进一步的优化,经仔细观察可以发现:这道题中存在着一个上限值(Min{100 div A, 100 div B, 100 div C}),这是一个很好的判断条件,他可以帮我们尽早地求出最优解。为什么这样说呢?因为,在动态规划开始前,我们可以先用贪心法算出N条生产线可以生产的套数,如果大于上限值则可以直接输出上限值并退出。否则再调用动态规划,而在动态规划求解的过程中,也可以在每完成一阶段工作便和上限值进行比较,若大于等于上限值就退出,这样一来,就可以尽早的求出解并结束程序。

#include
#include
#include
#include
using namespace std;

int a,b,c,p1,p2,p3,n,f[11][101][101],t[11];

int main()
{
    freopen("wiki.in","r",stdin);
    freopen("wiki.out","w",stdout);
    scanf("%d%d%d%d%d%d%d",&a,&b,&c,&p1,&p2,&p3,&n);
    for(int i=1;i<=n;i++) scanf("%d",&t[i]);
    int minn=min(100/a,min(100/b,100/c));
    memset(f,-1,sizeof(f));
    f[0][0][0]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=minn*a;j++)
        {
            for(int k=0;k<=minn*b;k++)
            {
                for(int j1=0;j1<=j;j1++)
                {
                    for(int k1=0;k1<=k;k1++)
                    {
                        if(f[i-1][j-j1][k-k1]!=-1 && t[i]-j1*p1-k1*p2>=0)
                        {
                            if(f[i][j][k] >= minn*c)
                            {
                                j1=j+1;
                                break;
                            }
                            f[i][j][k]=max(f[i][j][k],f[i-1][j-j1][k-k1]+(t[i]-j1*p1-k1*p2)/p3);
                        }
                    }
                }
            }
        }    
    }   
    int ans=0;
    for(int i=0;i<=minn*a;i++)
        for(int j=0;j<=minn*b;j++)
        {
            ans=max(ans,min(i/a,min(j/b,f[n][i][j]/c)));
        }
    printf("%d",ans);
}


你可能感兴趣的:(wiki-1260-快餐问题)