最佳课题选择【DP】

题目描述

Matrix67要在下个月交给老师n篇论文,论文的内容可以从m个课题中选择。由于课题数有限,Matrix67不得不重复选择一些课题。完成不同课题的论文所花的时间不同。具体地说,对于某个课题i,若Matrix67计划一共写x篇论文,则完成该课题的论文总共需要花费Ai*x^Bi个单位时间(系数Ai和指数Bi均为正整数)。给定与每一个课题相对应的Ai和Bi的值,请帮助Matrix67计算出如何选择论文的课题使得他可以花费最少的时间完成这n篇论文。

输入输出格式

输入格式:
第一行有两个用空格隔开的正整数n和m,分别代表需要完成的论文数和可供选择的课题数。

以下m行每行有两个用空格隔开的正整数。其中,第i行的两个数分别代表与第i个课题相对应的时间系数Ai和指数Bi。

输出格式:
输出完成n篇论文所需要耗费的最少时间。

输入输出样例

输入样例#1: 复制
10 3
2 1
1 2
2 1
输出样例#1: 复制
19
说明

【样例说明】

4篇论文选择课题一,5篇论文选择课题三,剩下一篇论文选择课题二,总耗时为2*4^1+1*1^2+2*5^1=8+1+10=19。可以证明,不存在更优的方案使耗时小于19。

【数据规模与约定】

对于30%的数据,n<=10,m<=5;

对于100%的数据,n<=200,m<=20,Ai<=100,Bi<=5。

分析:按照一贯的DP套路,设f【i】【j】表示前i篇论文在前j种课题中花费的最少时间(答案:f【n】【m】)。
先从小问题分析,假设j为1答案是什么?不难想到:f【i】【1】=a【1】*x^b【1】。这也就是等下我们要初始化的内容了。
假设等于2呢?先考虑i等于2的情况:有三种策略:1.在第一个课题选择2篇论文;2.在第二个课题选择2篇论文;3.在第一个课题选择一篇论文,在第二个课题选择一篇论文。三个当中选择最小的就是f【2】【2】的答案了。
那么继续拓展到j等于3,4…N的情况(请读者自行拓展)。
拓展完之后我们发现,对于一般情况f【i】【j】,有若干个选择:
x1篇在第一个课题,x2篇在第二个课题,x3篇在第三个课题…xj篇在第j个课题(x1+x2+x3…+xj==i)
那么怎么表示这么多选择呢?其实我们只用考虑最后一个xj的值就好了(因为f【i-1】的最优值已经计算好了),那么就非常简单了,时间复杂度O(n^3)
代码如下:

#include<bits/stdc++.h>
using namespace std;
int n,m;
long long a[30],b[30],f[210][30];//记住开long long,别忘了 
inline long long cifang(int x,long long zs)//计算x^zs
{
    long long ans=(long long)x;
    for(int i=2;i<=zs;i++)
    ans*=(long long)x;
    return ans;
}
inline long long _min(long long x,long long y)
{
    if(x>y) return y;
    return x;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%lld%lld",&a[i],&b[i]);
    }
    for(int i=0;i<=n;i++) f[i][1]=a[1]*cifang(i,b[1]);//初始化 
    for(int i=2;i<=m;i++)//枚举课题 
    {
        for(int j=0;j<=n;j++)//枚举论文 
        {
            f[j][i]=1e15;//初始化 
            for(int k=0;k<=j;k++)//枚举分配在第i个课题的论文篇数 
            {
                f[j][i]=_min(f[j][i],f[j-k][i-1]+a[i]*cifang(k,b[i]));//更新最优解 
            }
        }
    }
    printf("%lld",f[n][m]);//输出答案 
    return 0;
}

谢谢各位

posted @ 2018-04-06 19:15  最爱丁珰  阅读(31)  评论(0编辑  收藏  举报