$$
dp(i, j) = \min (dp(i, k - 1) + dp(k, j) + c * a(k)), k \in (i, j], c = a(i) * a(j + 1).
$$
其中,$a(i)$ 是 $i$ 号矩阵的行数,$a(i + 1)$ 是 $i$ 号矩阵的列数。
intmain(){u32t,n;cin>>t;for(u32i=0;i<t;++i){cin>>n;vector<u64>a(n+1);cin>>a[0]>>a[1];for(u32j=2;j<=n;++j){cin>>a[j]>>a[j];}vectordp(n,vector<u64>(n));for(u32j=0;j<n;++j){dp[j][j]=0;}for(u32s=1;s<n;++s){for(u32i=0,j=s;j<n;++i,++j){autoc=a[i]*a[j+1];// c is the coefficient "a[i] * a[j]". --Constant Optimizationautod=dp[i][j-1]+c*a[j];// d is current max, initialized with k = j;for(u32k=i+1;k<j;++k)if(autot=dp[i][k-1]+dp[k][j]+c*a[k];d>t)d=t;dp[i][j]=s;}}cout<<dp[0][n-1]<<'\n';}}
记忆化搜索.算法导论P210例题
再次推荐
functools.lru_cache
,写DP的时候用来做记忆化搜索真的超好用供参考
INF开太小WA了两次,做法就是动态规划
include
include
include
include
include
include
include
include
define REP(i,n) for(int i=0;i<(n);++i)
define FOR(i,a,b) for (int i=a;i<=b;i++)
define mem(a) memset(a,0,sizeof(a))
define db(x) cout << x << endl
define dbb(x,y) cout << x << ” ” << y << endl
using namespace std;
typedef long long ll;
int n,T;
ll f[60][60];
ll a[60],b[60];
const ll inf =4611686018427387904;
ll solve(int l, int r) {
if (f[l][r] != -1) return f[l][r];
if (l == r - 1) return f[l][r] = a[l] * b[l] * b[r];
if (l == r) return f[l][r] = 0;
long long ans = inf;
for (int x = l ; x < r; x++){
ans = min(ans, solve(l, x) + solve(x+1, r) + a[l] * b[x] * b[r]);
}
return f[l][r] = ans;
}
int main() {
scanf(“%d”, &T);
while (T–) {
cin >> n;
REP(i,n)
cin >> a[i] >> b[i];
memset(f, 0xff, sizeof(f));
cout << solve(0,n-1)<<endl;
}
return 0;
}
我的思路和其他各位差不多,但我是从 0 开始数数的(滑稽)。
$$
dp(i, j) = \min (dp(i, k - 1) + dp(k, j) + c * a(k)), k \in (i, j], c = a(i) * a(j + 1).
$$
其中,$a(i)$ 是 $i$ 号矩阵的行数,$a(i + 1)$ 是 $i$ 号矩阵的列数。
动态规划。相信oj,直接循环就可以AC,完全不用优化代码。
思路:
dp[i][j]
表示从第i个矩阵到第j个矩阵的最小乘法次数,则结果只需输出dp[1][n]
即可。用num[x]
存储矩阵大小。显然,当i=j时
dp[i][j]
=0(因为不需要计算乘法),而当i < j时,可能出现j-i种情况,其中“断点”设为k,则dp[i][j]=min(dp[i][k]+dp[k+1][j]+num[i-1]*num[k]*num[j])
。附C代码: