1)表达式上的dp
问题:一个n*m矩阵由n行m列共n*m个数排列而成。两个矩阵A和B可以相乘当且仅当A的列数等于B的行数。一个N*M的矩阵乘以一个M*P的矩阵等于一个N*P的矩阵,运算量为nmp。
矩阵乘法满足结合律,A*B*C可以表示成(A*B)*C或者是A*(B*C),两者的运算量却不同。例如当A=2*3 B=3*4 C=4*5时,(A*B)*C=64而A*(B*C)=90。显然第一种顺序节省运算量。
现在给出N个矩阵,并输入N+1个数,第i个矩阵是a[i-1]*a[i]。
题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=284
分析:跟区间dp一样,这个问题是在一个区间上进行动态规划的,假如我们要求 b-->e 区间上的最小值,我们找到一个中间区间 i ,让 b-->i 和 i -->e 的值最小,然后继续向下找
这是一个搜索的思想,可以用记忆话搜索降低复杂度。
其中的转移方程是 f【i】【j】 = f【i】【k】+f【k】【j】 + a [ i ] . x * a [ k ] . y * a [ j ] . y
如果不要求输出路径的话,可以用dp写,按照 j -- i 递增的顺序递推、
如果要求答应的路径的话,只能用记忆化搜索写,当然路径也是用递归写。
AC代码:
#include <cstdio> #include <cstring> using namespace std; const int N = 15; const int inf = 0x3f3f3f3f; struct Node { int x,y; }; Node a[N]; int f[N][N],path[N][N]; int dp(int b,int e) { if(b>=e) return 0; int& max=f[b][e]; if(max!=0) return max; max=inf; for(int i=b; i<e; i++) { int tmp=dp(b,i)+dp(i+1,e)+a[b].x*a[i].y*a[e].y; ///转移方程 if(tmp<max) { max=tmp; path[b][e]=i; } } return max; } int print(int b,int e) { if(b==e) printf("A%d",b); else { printf("("); print(b,path[b][e]); printf(" x "); print(path[b][e]+1,e); printf(")"); } } int main() { int n,cas=1; while(~scanf("%d",&n)&&n) { for(int i=1; i<=n; i++) scanf("%d%d",&a[i].x,&a[i].y); memset(f,0,sizeof(f)); memset(path,0,sizeof(path)); printf("Case %d: ",cas++); dp(1,n); print(1,n); printf("\n"); } return 0; }