1. 程式人生 > 實用技巧 >題解 CodeVS1251 【括號】

題解 CodeVS1251 【括號】

題目描述:

計算乘法時,我們可以新增括號,來改變相乘的順序,比如計算 $x_1,x_2,...,x_{n-1},x_n$ 的積,我們可以:

$(x_1(x_2(...(x_{n-1}x_n))))$......$((((x_1x_2)...)x_{n-1})x_n)$

你的任務是程式設計求出所有這樣的添括號的方案。

輸入格式:

輸入檔案第一行是一個數 $n$ $(1<=n<=10)$,表示有 $n$ 個變數,之後 $n$ 行每行一個變數的名字。

輸出格式:

輸出所有的新增括號的方案。注意:單個字元不要加括號,兩個字元相乘中間要有乘號。

題解:

本題不難$dfs$計算答案,難的是輸出答案

我們可以先從如何計算答案入手,易得,區間 $l-r$ 的方法數計算公式為:

$f(l,r)=\sum_{i=l}^{r-1}f(l,i)*f(i+1,r)$

因為答案數是由子區間得來的,所以具體答案也是從子區間得來的,我們可以定義 $ans(l,r,k)$ 為區間 $l$ 到 $r$ 的第 $k$ 個答案。如果我們是使用 $string$ 來記錄答案的話答案的獲得公式即為:

$ans(l,r,x)=ans(l,i,y)+ans(i+1,r,z)$,其中$(l<=i<r)(x,y,z$為任意的存在的答案下標$)$

如果擔心超空間,可以嘗試儲存序號,將“$($”標號為 $11$ ,將“$)$”標號為 $12$ ,將“$*$”標號為 $13$ ,只不過這樣就不能使用優秀的$string$來更新答案了。

程式碼如下:

#include<bits/stdc++.h>
using namespace std;
int n;
string s[15];
vector <string> ans[15][15];
void dfs(int l,int r)
{
	if(ans[l][r].size())
	return ;
	for(int i=l;i<r;++i)
	{
		dfs(l,i);
		dfs(i+1,r);
	}
	for(int i=l;i<r;++i)
	{
		for(int j=0;j<(int)ans[l][i].size();++j)
		{
			for(int k=0;k<(int)ans[i+1][r].size();++k)
			{
				ans[l][r].push_back("("+ans[l][i][j]+ans[i+1][r][k]+")");
			}
		}
	}
//	printf("%d %d\n",l,r);
//	for(int i=0;i<(int)ans[l][r].size();++i)
//	cout<<ans[l][r][i]<<'\n';
	return ;
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;++i)
	{
		cin>>s[i];
		ans[i][i].push_back(s[i]);
		if(i>1)
		ans[i-1][i].push_back("("+s[i-1]+"*"+s[i]+")");
	}
	dfs(1,n);
	for(int i=0;i<(int)ans[1][n].size();++i)
	cout<<ans[1][n][i]<<'\n';
	return 0;
}