nyoj737石子合并(一)
先得出区间为1和2时的结果。用arr[i][j]记录i,j内的和。dp[i][j]记录i,j区间全加起来的最小花费。那么区间大小为1和2时都是明显的。为3时枚举断点。其中一个区间大小为1也是可行的。
虽然复杂度为n^3,不过比n!好。
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #include <iomanip> #include <cstring> #include <map> #include <queue> #include <set> #include <cassert> using namespace std; const double EPS=1e-8; const int SZ=220,INF=0x7FFFFFFF; typedef long long lon; int n,arr[SZ][SZ],dp[220][220]; void init() { //cin>>n; for(int i=1;i<=n;++i)cin>>arr[i][i]; } void work() { for(int i=1;i+1<=n;++i) { int r=i+1; arr[i][r]=dp[i][r]=arr[i][i]+arr[r][r]; } for(int len=3;len<=n;++len) { for(int i=1;i<=n;++i) { int r=i+len-1; if(r>n)break; dp[i][r]=INF; for(int j=i;j+1<=r;++j) { arr[i][r]=arr[i][j]+arr[j+1][r]; dp[i][r]=min(dp[i][r],dp[i][j]+dp[j+1][r]+arr[i][j]+arr[j+1][r]); } } } cout<<dp[1][n]<<endl; } int main() { std::ios::sync_with_stdio(0); //freopen("d:\\1.txt","r",stdin); //lon casenum; //cin>>casenum; //for(lon time=1;time<=casenum;++time) for(lon time=1;cin>>n;++time) { init(); work(); } return 0; }