RQNOJ 117 最佳课题选择:多重背包
题目链接:https://www.rqnoj.cn/problem/117
题意:
NaCN_JDavidQ要在下个月交给老师n篇论文,论文的内容可以从m个课题中选择。
由于课题数有限,NaCN_JDavidQ不得不重复选择一些课题。
对于某个课题i,若NaCN_JDavidQ计划一共写x篇论文,则完成该课题的论文总共需要花费Ai*(x^Bi)个单位时间(系数Ai和指数Bi均为正整数)。
给定与每一个课题相对应的Ai和Bi的值,请帮助NaCN_JDavidQ计算出如何选择论文的课题使得他可以花费最少的时间完成这n篇论文。
题解:
转化问题:
(将对象由论文转化为课题)
有m个课题。
对于每个课题,你可以写任意篇论文。
问你恰好写完n篇论文的最小时间。
表示状态:
dp[i][j] = min time
i:考虑到第i个课题
j:已经完成了j篇论文
找出答案:
ans = dp[m][n]
如何转移:
now: dp[i][j]
dp[i+1][j+k] = min dp[i][j] + a[i]*(k^b[i])
第i个课题写了k篇论文
边界条件:
dp[0][0] = 0
others = -1
注:本题会爆int。。。
AC Code:
1 // state expression: 2 // dp[i][j] = min time 3 // i: considering ith project 4 // j: finished j papers 5 // 6 // find the answer: 7 // dp[m][n] 8 // 9 // transferring: 10 // now: dp[i][j] 11 // dp[i+1][j+k] = min dp[i][j] + a[i]*k^b[i] 12 // 13 // boundary: 14 // dp[0][0] = 0 15 // others = -1 16 #include <iostream> 17 #include <stdio.h> 18 #include <string.h> 19 #define MAX_N 205 20 #define MAX_M 25 21 22 using namespace std; 23 24 int n,m; 25 int a[MAX_M]; 26 int b[MAX_M]; 27 long long dp[MAX_M][MAX_N]; 28 29 void read() 30 { 31 cin>>n>>m; 32 for(int i=0;i<m;i++) 33 { 34 cin>>a[i]>>b[i]; 35 } 36 } 37 38 long long quick_pow(long long n,long long k) 39 { 40 long long ans=1; 41 while(k) 42 { 43 if(k&1) 44 { 45 ans*=n; 46 } 47 n*=n; 48 k>>=1; 49 } 50 return ans; 51 } 52 53 void solve() 54 { 55 memset(dp,-1,sizeof(dp)); 56 dp[0][0]=0; 57 for(int i=0;i<m;i++) 58 { 59 for(int j=0;j<=n;j++) 60 { 61 if(dp[i][j]!=-1) 62 { 63 for(int k=0;j+k<=n;k++) 64 { 65 long long now=dp[i][j]+a[i]*quick_pow(k,b[i]); 66 if(dp[i+1][j+k]==-1 || dp[i+1][j+k]>now) 67 { 68 dp[i+1][j+k]=now; 69 } 70 } 71 } 72 } 73 } 74 } 75 76 void print() 77 { 78 cout<<dp[m][n]<<endl; 79 } 80 81 int main() 82 { 83 read(); 84 solve(); 85 print(); 86 }