160 条题解
-
6
2351599120 LV 9 @ 7 年前
简单区间DP
25ms -
69 年前@
要说的都在程序里:
```c++
#include<iostream>
using namespace std;int n,head[201],tail[201],f[201][201];
//f[i][j]为起始为i终点为j的链融合生成的最大能量
//head和tail要拓展数组不然越界要考虑模
//珠子 1 2 3 4 5(1) 6(2) 7(3)
//head 1 3 5 7 1 3 5
//tail 3 5 7 1 3 5 7
//没有再考虑4是因为不需要,枚举不到void read()
{
int i,j,k,len,max1;cin>>n;
cin>>head[1];
for(i=2; i<=n; i++)
{
cin>>head[i];tail[i-1]=head[i];
}
tail[n]=head[1];//读入for(i=n+1; i<=2*n-1; i++)
{
head[i]=head[i-n];
tail[i]=tail[i-n];
}//拓展数组for(len=1; len<=n; len++)//枚举链长
for(i=1; i<=2*n-1-len; i++)//枚举起始位置
{
j=i+len;//结束位置for(k=i; k<j; k++)//寻找在中间某一位置断开,把两边合并
f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+head[i]*tail[k]*tail[j]);
//从i到j的最大能量=max(当前能量,从i到k的最大能量+从k+1到j的最大能量
//+两颗珠子合并释放的能量)
//注意我们把i到k,k+1到j看做两颗已经合并的珠子,只需把这两颗合并
}max1=0;
for(i=1; i<=n; i++)
if(f[i][n+i-1]>max1)
max1=f[i][n+i-1];//枚举起始点找最大cout<<max1<<endl;
return;
}int main()
{
read();
return 0;
}
``` -
210 年前@
var
i,j,k,sum,n:longint;
a:array[1..101]of longint;
f:array[1..2000,1..2000]of longint;
function max(a,b:longint):longint;
begin
if a>b then
exit(a)
else
exit(b);
end;
begin
read(n);
for i:=1 to n do
f[i,i]:=0;
for i:=1 to n do
begin
read(a[i]);
a[i+n]:=a[i];
end;
for i:=2*n-3 downto 1 do
for j:=i+2 to n+i do
for k:=i+1 to j-1 do
f[i,j]:=max(f[i,j],f[i,k]+f[k,j]+a[i]*a[k]*a[j]);
for i:=1 to n do
sum:=max(f[i,i+n],sum);
writeln(sum);
end. -
16 年前@
-
17 年前@
简单处理成环,之后简单DP.
-
18 年前@
-
04 年前@
-
06 年前@
-
07 年前@
环形区间动规,类比矩阵连乘,动规方程式:
F(i,j)=M(i)*M(j)*M(k)+F(i,k)+F(k+1,j)
CK()是用来处理越界数据的,省一点空间,虽然才10^4。 -
07 年前@
一个很简单的区间DP,主要是环变线,想说两点:
1. 用专门的结构体存比较好理解。
2. 答案区间是要尽可能枚举到最右边的,虽然最终答案的区间左端点必定是在【1,N】,但在逐级转移中也可能会出现【N+i,N+j】的一个最优贡献,要考虑到位。 -
07 年前@
-
08 年前@
-
08 年前@
#include <cstdio>
#include <algorithm>
#define M 110
using std::max;int m=0,n,v[M],f[M][M]={0};
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&v[i]);
for(int j=2;j<=n;j++)
for(int i=0;i<n;i++)
for(int k=1;k<j;k++)
f[i][j]=max(f[i][j],f[i][k]+f[(i+k)%n][j-k]+v[(i+k)%n]*v[i]*v[(i+j)%n]);
for(int i=0;i<n;i++)
m=max(m,f[i][n]);
printf("%d",m);
return 0;
} -
08 年前@
编译成功
测试数据 #0: Accepted, time = 0 ms, mem = 680 KiB, score = 10
测试数据 #1: Accepted, time = 0 ms, mem = 680 KiB, score = 10
测试数据 #2: Accepted, time = 15 ms, mem = 680 KiB, score = 10
测试数据 #3: Accepted, time = 15 ms, mem = 676 KiB, score = 10
测试数据 #4: Accepted, time = 15 ms, mem = 680 KiB, score = 10
测试数据 #5: Accepted, time = 0 ms, mem = 680 KiB, score = 10
测试数据 #6: Accepted, time = 15 ms, mem = 680 KiB, score = 10
测试数据 #7: Accepted, time = 0 ms, mem = 680 KiB, score = 10
测试数据 #8: Accepted, time = 0 ms, mem = 680 KiB, score = 10
测试数据 #9: Accepted, time = 0 ms, mem = 680 KiB, score = 10
Accepted, time = 60 ms, mem = 680 KiB, score = 100
返回代码界面 | 关闭#include<cstdio>
#include<algorithm>
using namespace std;
int n,f[209][209],a[209],ans=0;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i) {scanf("%d",&a[i]);a[i+n]=a[i];}
for(int i=n*2-1;i>=1;--i)
{
for(int j=i+1;j<n*2&&j-i<n;++j)
{
for(int k=i;k<j;k++)
{
f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+a[i]*a[k+1]*a[j+1]);
}
ans=max(ans,f[i][j]);
}
}
printf("%d",ans);
return 0;
} -
08 年前@
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<cstdlib>
#include<string>
#include<bitset>
#include<iomanip>
#define ll long long
using namespace std;
int n,sum,ans = 0;
int a[205],f[205][205];
int juhe(int i,int k,int j){
sum = a[i] * a[k + 1] * a[j + 1];
return sum;
}
int main(){
//freopen("p1312.in","r",stdin);
//freopen("p1312.out","w",stdout);
scanf("%d",&n);
for(int i = 1;i <= n;i++){
scanf("%d",&a[i]);
a[i + n] = a[i];
}
for(int i = 1;i <= 2*n;i++)
f[i][i] = 0;
for(int j = 1;j < 2*n;j++)
for(int i = j;i >= max(1,j - n + 1);i--){
for(int k = i;k < j;k++){
f[i][j] = max(f[i][j],f[i][k]+f[k+1][j]+juhe(i,k,j));
}
}for(int i = 1;i<=n;i++)
ans=max(ans,f[i][i+n-1]);
printf("%d\n",ans);
return 0;
} -
08 年前@
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
const int N = 105;
const int M = N << 1;
int n,res = 0,head[M],f[M][M] = {0};
int main()
{
scanf("%d",&n);
for(int i = 1;i <= n;i++)
{
scanf("%d",&head[i]);
head[n + i] = head[i];
}
for(int p = 1;p < n;p++)
for(int i = 1;i < ((n << 1) - 1);i++)
for(int j = min(i + p,(n << 1) - 1),k = i;k < j;k++)
f[i][j] = max(f[i][j],f[i][k] + f[k + 1][j] + head[i] * head[k + 1] * head[j + 1]);
for(int i = 1;i <=n;i++)
res = max(res,f[i][n + i - 1]);
printf("%d\n",res);
return 0;
} -
09 年前@
多开1倍的数组,26行搞定
#include <iostream>
using namespace std;
int n,a[205],b[205],f[205][205],x;
int main()
{
cin >> n;
for(int i = 1 ; i <= n ; i++ )
{
cin>>a[i];
a[i+n]=a[i];
}
b[n]=a[1];
for(int i = 1 ; i < n ; i++ )
b[i]=b[i+n]=a[i+1];
for(int c=1;c<n;c++)
for(int i=1;i<=2*n-c;i++)
{
x=i+c;
for(int j=i;j<x;j++)
f[i][x]=max(f[i][x],f[i][j]+f[j+1][x]+a[i]*b[j]*b[x]);
}
for(int i=1;i<=n;i++)
f[0][0]=max(f[i][i+n-1],f[0][0]);
cout<<f[0][0];
return 0;
} -
09 年前@
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 200 + 10;int a[MAXN], f[MAXN][MAXN];
int main()
{
int n, ans = 0;
scanf("%d", &n);
for(int i=1; i<=n; i++){
scanf("%d", &a[i]);
a[i+n] = a[i];
}
for(int j=1; j<2*n; j++){
for(int i=j; i>=max(1, j-n+1); i--){
if(i == j) f[i][j] = 0;
for(int k=i; k<j; k++)
f[i][j] = max(f[i][j], f[i][k]+f[k+1][j]+a[i]*a[k+1]*a[j+1]);
}
if(j >= n)
ans = max(ans, f[j-n+1][j]);
}
printf("%d", ans);
return 0;
} -
09 年前@
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
using namespace std;
int a[1000],f[1000][1000];
int n;
int main()
{
memset(f,0,sizeof(f));
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
a[i+n]=a[i];
}
int maxn=0;
for(int i=2;i<=n+n;i++){
for(int j=i-1;i-j<n&&j>=1;j--){
for(int k=j;k<i;k++){
f[j][i]=max(f[j][i],f[j][k]+f[k+1][i]+a[j]*a[k+1]*a[i+1]);
}
maxn=max(maxn,f[j][i]);
}
}
//for(int i=1;i<=n;i++)maxn=max(maxn,f[i][n+i-1]);
cout<<maxn;
}
只要将一条项链【1,n】连成【1,2n】的一条链即可