环状处理+区间dp得解,注意答案需要枚举判断出以哪一颗珠子开始最大。
状态转移方程为:
dp[j][i] = max(E[j]*E[k+1]*E[i+1]+dp[j][k]+dp[k+1][i],dp[j][i])
j是开始的一颗珠子,i是结束的一颗珠子。
相当于用k截开每两颗珠子计算最大区间值。
#include<bits/stdc++.h> using namespace std; #define ll long long #define din(x) scanf("%lf",&x) #define dout(x) printf("%lf",x) #define in(x) scanf("%d",&x) #define lin(x) scanf("%lld",&x) #define out(x) printf("%d",x) #define lout(x) printf("%lld",x) #define sin(x) scanf("%s",x) #define chin(x) scanf("%c",&x) #define sout(x) printf("%s",x) #define chout(x) printf("%c",x) #define ko putchar(' ') #define ex putchar('\n') const int MAXN = 105; int n; int dp[MAXN*2][MAXN*2]; int E[MAXN*2]; int main() { in(n); for(int i = 1;i <= n;i++) { in(E[i]); E[i+n] = E[i]; } E[0] = E[n]; for(int i = 1;i <= 2*n;i++) { for(int j = i;j >= 1 && j > i-n;j--) { for(int k = j;k < i;k++) { dp[j][i] = max(E[j]*E[k+1]*E[i+1]+dp[j][k]+dp[k+1][i],dp[j][i]); } } } int ans = 0; for(int i = 1;i <= n;i++) { ans = max(dp[i][i+n-1],ans); } out(ans); return 0; }
一道典型的分组背包题。
相当于01背包中加了一堆“附件”,实质上代码相当于枚举每个主件,看是取一个主件就好,还是取主件和其第一个附件,还是取主件和其第二个附件,亦或者是全都要(主件及其第一,二个附件)。
状态转移方程就是依照上面思路走的,直接套01模板就行:
if(j >= a[i]) f[j] = max(f[j],f[j-a[i]] + a[i]*h[i]);
if(j >= a[i] + a1[i]) f[j] = max(f[j],f[j - a[i] - a1[i]] + a[i]*h[i] + a1[i]*h1[i]);
if(j >= a[i] + a2[i]) f[j] = max(f[j],f[j - a[i] - a2[i]] + a[i]*h[i] + a2[i]*h1[i]);
if(j >= a[i] + a1[i] + a2[i]) f[j] = max(f[j],f[j-a[i]-a1[i]-a2[i]] + a[i]*h[i] + a1[i]*h1[i] + a2[i]*h2[i]);
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; #define ll long long #define din(x) scanf("%lf",&x) #define dout(x) printf("%lf",x) #define lin(x) scanf("%lld",&x) #define in(x) scanf("%d",&x) #define sin(x) scanf("%s",x) #define chin(x) scanf("%c",&x) #define out(x) printf("%d",x) #define lout(x) printf("%lld",x) #define sout(x) printf("%s",x) #define ex putchar('\n') #define ko putchar(' ') const int MAXN = 100; int a[MAXN],a1[MAXN],a2[MAXN]; int h[MAXN],h1[MAXN],h2[MAXN]; int f[32005]; int n,m; void dp() { for(int i = 1;i <= m;i++) { for(int j = n;j >= a[i];j--) { if(j >= a[i]) f[j] = max(f[j],f[j-a[i]] + a[i]*h[i]); if(j >= a[i] + a1[i]) f[j] = max(f[j],f[j - a[i] - a1[i]] + a[i]*h[i] + a1[i]*h1[i]); if(j >= a[i] + a2[i]) f[j] = max(f[j],f[j - a[i] - a2[i]] + a[i]*h[i] + a2[i]*h1[i]); if(j >= a[i] + a1[i] + a2[i]) f[j] = max(f[j],f[j-a[i]-a1[i]-a2[i]] + a[i]*h[i] + a1[i]*h1[i] + a2[i]*h2[i]); } } } int main() { // freopen("budget.in","r",stdin); // freopen("budget.out","w",stdout); in(n);in(m); for(int i = 1;i <= m;i++) { int v,p,q; in(v);in(p);in(q); if(q == 0) { a[i] = v; h[i] = p; } else { if(!a1[q]) { a1[q] = v; h1[q] = p; } else { a2[q] = v; h2[q] = p; } } } dp(); out(f[n]); return 0; }
一道题意十分复杂的模拟题,实际上并没有用什么特别的算法,就是单纯的模拟。
意思大概是:
1、给了n个工件,每个工件要在总共m个机器上每个机器处理一次。
2、给了工件放上去的顺序,但注意不是时间顺序。
3、每个工件每次处理都有一个指定的机器,所需的时间,处理工序必须按给的机器顺序。
4、(划重点)前面的工件(设为1号)若处理时间很长,长到足以让下面一个需要在某一个机器上处理的工件(设为2号)所需时间比1号在另一机器上处理的时间还要短的话,由于一号虽然接下来要在此机器上处理,但由于上一次处理还没有完,于是2号就可以先于一号在此机器上处理(反正影响不到1号)。
理解了上面的就可以写出这样的代码:
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; #define ll long long #define din(x) scanf("%lf",&x) #define dout(x) printf("%lf",x) #define lin(x) scanf("%lld",&x) #define in(x) scanf("%d",&x) #define sin(x) scanf("%s",x) #define chin(x) scanf("%c",&x) #define out(x) printf("%d",x) #define lout(x) printf("%lld",x) #define sout(x) printf("%s",x) #define ex putchar('\n') #define ko putchar(' ') const int MAXN = 25; const int len = 500; int n,m; int ans = 0; int a[len],rank[len]; int mac[MAXN][MAXN],t[MAXN][MAXN],cnt[MAXN]; int last[MAXN]; bool worked[MAXN][len]; bool check(int from,int lasttime,int id) { for(int i = from;i < from + lasttime;i++) { if(worked[id][i]) { return 0; } } return 1; } int main() { in(m);in(n); int all = n*m; for(int i = 1;i <= all;i++) { in(a[i]); cnt[a[i]]++; rank[i] = cnt[a[i]]; } for(int l = 1;l <= 2;l++) { for(int i = 1;i <= n;i++) { for(int j = 1;j <= m;j++) { if(l == 1) in(mac[i][j]); else in(t[i][j]); } } } for(int i,j = 1;j <= all;j++) { int idx = a[j]; int id = mac[idx][rank[j]]; for(i = last[idx] + 1;;i++) { if(!worked[id][i]) { if(check(i,t[idx][rank[j]],id)) { break; } } } int end = i + t[idx][rank[j]]-1; for(i;i <= end;i++) { worked[id][i] = 1; } last[idx] = end; ans = max(ans,end); } out(ans); return 0; }