• P2308 添加括号(dfs记录dp路径)


    传送门

    (一看肯定是区间DP(因为和和合并石子很相似,都要加n-1次))

    (转移方程为(其中he[i][j]是i到j的和))

    [dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+he[i][j]) ]

    (问题Ⅰ.如何输出括号)

    (在转移的时候,我们可以用vis[i][j]来记录i到j合并的断点k,所以可以分别递归i至k和k+1至r)

    void dfs(int l,int r)
    {
    	if(l==r)	return;
    	z[l]++,y[r]++;//记录左右括号 
    	dfs(l,vis[l][r]);
    	dfs(vis[l][r]+1,r);
    }
    

    那求中间和也是一样的道理。

    void DFS(int l,int r)
    {
    	if(l==r)	return;
    	DFS(l,vis[l][r]);
    	DFS(vis[l][r]+1,r);
    	cout<<he[l][r]<<" ";
    }
    

    完整代码

    #include <bits/stdc++.h>
    using namespace std;
    int n,dp[22][22],a[22],he[22][22],vis[22][22];
    int z[22],y[22];
    void dfs(int l,int r)
    {
    	if(l==r)	return;
    	z[l]++,y[r]++;//记录左右括号 
    	dfs(l,vis[l][r]);
    	dfs(vis[l][r]+1,r);
    }
    void DFS(int l,int r)
    {
    	if(l==r)	return;
    	DFS(l,vis[l][r]);
    	DFS(vis[l][r]+1,r);
    	cout<<he[l][r]<<" ";
    }
    int main()
    {
    	cin>>n;
    		memset(dp,20,sizeof(dp));
    	for(int i=1;i<=n;i++)	cin>>a[i],dp[i][i]=0;
    	for(int i=1;i<=n;i++)
    	{
    		int sumn=0;
    		for(int j=i;j<=n;j++)
    		{
    			sumn+=a[j];
    			he[i][j]=sumn;
    		}
    	}
    	for(int l=2;l<=n;l++)
    	for(int i=1;i+l-1<=n;i++)
    	{
    		int j=i+l-1;
    		for(int k=i;k<=j-1;k++)
    		{
    			if(dp[i][j]>=dp[i][k]+dp[k+1][j]+he[i][j])
    			{
    				dp[i][j]=dp[i][k]+dp[k+1][j]+he[i][j];
    				vis[i][j]=k;//在k点分割的 
    			}
    		}
    	}
    	dfs(1,n);
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=z[i];j++)	cout<<"(";
    		cout<<a[i];
    		for(int j=1;j<=y[i];j++)	cout<<")";
    		if(i!=n)	cout<<"+";
    	}
    	cout<<endl;
    	cout<<dp[1][n]<<endl;
    	DFS(1,n);
    }
    
  • 相关阅读:
    C#里partial关键字的作用
    Xamarin.Android之布局文件智能提示问题
    C语言文件操作
    CArray
    Unicode和多字节的相互转换
    可变参数问题研究
    VC6.0支持UNICODE的步骤
    Unicode编码表
    @@
    内存映射文件原理
  • 原文地址:https://www.cnblogs.com/iss-ue/p/12713034.html
Copyright © 2020-2023  润新知