// uva348 最优矩阵链乘 // 典型的区间dp // dp[i][j] 表示矩阵i到j链乘所得到的最小花费 // dp[i][j] = min(dp[i][k]+dp[k+1][j]+a[i].pl*a[k].pr*a[j].pr); // 在区间i到j上找一个k使得dp[i][k]+dp[k+1][j]这两部分的和在加上最后的 // a[i].pl*a[k].pr*p[i].pr的最小值; // 能有这样的状态关键是; P =A[1] * A[2] * .... * A[K] // 和 Q= A[K+1] * A[K+2] * .... * A[N] 这两部分的结果是不相互影响的, // 因此只需要分别让 P 和 Q 最优方法计算,最优子结构! // 边界时dp[i][i]=0; // // 这是一道痕经典的区间dp的题目,学会了用这种方法考虑问题 // 最后,还有就是递归打印,实在是十分奇妙。 // 还是挺高兴的呢。哎,继续练吧。。。。 #include <algorithm> #include <bitset> #include <cassert> #include <cctype> #include <cfloat> #include <climits> #include <cmath> #include <complex> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #include <deque> #include <functional> #include <iostream> #include <list> #include <map> #include <numeric> #include <queue> #include <set> #include <stack> #include <vector> #define ceil(a,b) (((a)+(b)-1)/(b)) #define endl '\n' #define gcd __gcd #define highBit(x) (1ULL<<(63-__builtin_clzll(x))) #define popCount __builtin_popcountll typedef long long ll; using namespace std; const int MOD = 1000000007; const long double PI = acos(-1.L); template<class T> inline T lcm(const T& a, const T& b) { return a/gcd(a, b)*b; } template<class T> inline T lowBit(const T& x) { return x&-x; } template<class T> inline T maximize(T& a, const T& b) { return a=a<b?b:a; } template<class T> inline T minimize(T& a, const T& b) { return a=a<b?a:b; } const int maxn = 1008; struct node { int pl; int pr; }a[maxn]; ll d[maxn][maxn]; int path[maxn][maxn]; int n; const ll inf = 0x4f4f4f4f4f4f4f4f; ll dp(int i,int j){ if (d[i][j]!=inf) return d[i][j]; ll& ans = d[i][j]; for (int k=i;k<j;k++){ ll res = dp(i,k)+dp(k+1,j)+(ll)a[i].pl*a[k].pr*a[j].pr; if (ans>res){ ans = res; path[i][j] = k; } } return ans; } void print(int i,int j){ if (i==j){ printf("A%d",i+1); return; } printf("("); for (int k=i;k<j;k++) if (path[i][j]==k){ print(i,k); printf(" x "); print(k+1,j); break; } printf(")"); //printf(")"); } int main() { int kase = 0; // freopen("G:\\Code\\1.txt","r",stdin); while(scanf("%d",&n)!=EOF&&n){ for (int i=0;i<n;i++) scanf("%d%d",&a[i].pl,&a[i].pr); // memset(d,0x4f,sizeof(d)); // memset(path,0,sizeof(path)); for (int i=0;i<n;i++) for (int j=0;j<n;j++){ path[i][j]=0; d[i][j]=inf; } for (int i=0;i<n;i++) d[i][i]=0; dp(0,n-1); //printf("%lld\n",dp(0,n-1)); printf("Case %d: ",++kase); print(0,n-1); puts(""); } return 0; }
时间: 2024-10-06 14:38:20