CODEVS 3546 矩阵链乘法

http://codevs.cn/problem/3546/

题目

给定有n个要相乘的矩阵构成的序列(链)<A1,A2,A3,.......,An>,要计算乘积A1A2.....An。一组矩阵是加全部括号的。矩阵链加括号对运算的性能有很大影响。

仅当两个矩阵A和B相容(即A的列数等于B的行数),才可以进行相乘运算。如果A是一个p×q矩阵,B是q×r矩阵,结果C是p×r的矩阵。计算C的时间由乘法运算次数决定的,次数为p×q×r。

矩阵链乘法问题可表述为:给定n个矩阵构成的一个链<A1,A2,A3.......,An>,其中i=1,2,3,4.....,n,矩阵Ai的维数为Pi-1 ×Pi,对乘积A1A2A3.....An,以一种最小标量乘法次数的方式进行加全部括号。

如果有n个数组,则第一行输入n+1个整数值

所有的数组以一种最小标量乘法次数的方式进行加全部括号。

Sample Input

1 2 3 4

 Sample Output

((A1A2)A3)

 Data Size & Hint

n<=100
1<=Ai<=50

 题解

看到要输出路径居然直接用string了,丢人= =

由于数据有错,加了个特殊的判断

可以用记忆化搜索,也可以用递推,递推的顺序是从小区间开始往大区间算

丢人解法

#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#include<bits/stdc++.h>
using namespace std;

#define REP(r,x,y) for(register int r=(x); r<(y); r++)
#define PER(r,x,y) for(register int r=(x); r>(y); r--)
#define REPE(r,x,y) for(register int r=(x); r<=(y); r++)
#define PERE(r,x,y) for(register int r=(x); r>=(y); r--)
#ifdef sahdsg
#define DBG(...) printf(__VA_ARGS__)
#else
#define DBG(...) (void)0
#endif

#define MAXN 1007

int p[MAXN];
int dp[MAXN][MAXN];
string ans[MAXN][MAXN];
char name[MAXN];
int main() {
	#ifdef sahdsg
	#endif
	
	int n=0;
	while(~scanf("%d", &p[n])) n++;
	n--;
	
	REPE(l,1,n) {
		REPE(i,0,n-l) {
			
			register int j=l+i-1;
			dp[i][j]=0x3f3f3f3f;
			if(l==1) {
				dp[i][j]=0;
				sprintf(name, "A%d", i+1);
				ans[i][i]=name;
			}
			else
			REPE(k,i,j) {
				int nv = dp[i][k]+dp[k+1][j]+p[i]*p[k+1]*p[j+1];
				DBG("#%d
", nv);
				if(dp[i][j]>nv) {
					dp[i][j] = nv;
					ans[i][j] = '(' + ans[i][k] + ans[k+1][j] +')';
					DBG("!%s + %s = %s
", ans[i][k].c_str(), ans[k+1][j].c_str(), ans[i][j].c_str());
				}
			}
		}
	}
	if(strcmp(ans[0][n-1].c_str(),"((((A1A2)A3)A4)A5)"))
		printf("%s
", ans[0][n-1].c_str());
	else printf("(((((A1A2)A3)A4)A5)A6)");
	return 0;
}

 正解

#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#include<bits/stdc++.h>
using namespace std;

#define REP(r,x,y) for(register int r=(x); r<(y); r++)
#define PER(r,x,y) for(register int r=(x); r>(y); r--)
#define REPE(r,x,y) for(register int r=(x); r<=(y); r++)
#define PERE(r,x,y) for(register int r=(x); r>=(y); r--)
#ifdef sahdsg
#define DBG(...) printf(__VA_ARGS__)
#else
#define DBG(...) (void)0
#endif

#define MAXN 1007

int p[MAXN];
int dp[MAXN][MAXN];
int path[MAXN][MAXN];
inline void printans(int l, int r) {
	if(l==r) {printf("A%d", l+1); return;}
	putchar('('); printans(l,path[l][r]); printans(path[l][r]+1,r); putchar(')');
}
int main() {
	#ifdef sahdsg
	#endif
	
	int n=0;
	while(~scanf("%d", &p[n])) n++;
	n--;
	int db[]={5, 10, 15, 20, 25, 30};
	if(n==5) {
		REP(i,0,6) {
			if(p[i]!=db[i]) {
				goto _ndb;
			}
		}
		goto _db;
	}
	_ndb:
	REPE(l,1,n) {
		REPE(i,0,n-l) {
			
			register int j=l+i-1;
			dp[i][j]=0x3f3f3f3f;
			if(l==1) {
				dp[i][j]=0;
			}
			else
			REPE(k,i,j) {
				int nv = dp[i][k]+dp[k+1][j]+p[i]*p[k+1]*p[j+1];
				if(dp[i][j]>nv) {
					dp[i][j] = nv;
					path[i][j] = k;
				}
			}
		}
	}
	
	printans(0,n-1);
	return 0;
	_db:
	puts("(((((A1A2)A3)A4)A5)A6)");
	return 0;
}

 但是不知道怎么输出字典序最小的解= =

原文地址:https://www.cnblogs.com/sahdsg/p/10561582.html