ZOJ 2561 Order-Preserving Codes DP 四边形优化

来源:互联网 发布:创奇老照片修复软件 编辑:程序博客网 时间:2024/05/22 18:23

题目大意:给你n个字符出现的频次,做一棵类似哈夫曼的带权二叉树。但是和哈夫曼树不同的,每个字符的相对位置是不能改变的,在此前提下,使得权和最小。权和 == 每个字符出现的频次*这个字符代表的叶子节点到根的距离。

思路:

用dp[i][j]表示[i,j]这个区间,和成一棵二叉树,最小权和。显然dp[i][j] = min( dp[i][k-1] + dp[k][j] + sum[i][j] ),貌似是n^3的做法,但是很容易发现sum[][]满足四边形不等式,那么用四边形优化则可。关于四边形优化,网上还是很容易搜资料的,这里就不细说了。我感觉四边形优化比斜率优化好写,计算量少一些。

简单说说四边形吧

形如


如果w[][]满足四边形不等式,即:

如果i <= i’ <= j <= j’ ,一定有


这个时候,dp[][]也会满足四边形不等式,即:

dp[i][j] + dp[i’][j’] <= dp[i’][j] + dp[i][j’]

我们定义,dp[i][j]取得最优值的所有k,里面最大的为s[i][j]

由于dp[][]满足四边形不等式,所以有s[i][j-1] <= s[i][j] <= s[i+1][j]

利用s[][]的单调性,我们按dp[][]的长度做dp,可以得到n^2的算法



//#pragma comment(linker, "/STACK:102400000,102400000")#include<cstdio>#include<cstring>#include<vector>#include<queue>#include<cmath>#include<cctype>#include<string>#include<algorithm>#include<iostream>#include<ctime>#include<map>#include<set>using namespace std;#define MP(x,y) make_pair((x),(y))#define PB(x) push_back(x)typedef long long LL;//typedef unsigned __int64 ULL;/* ****************** */const LL INF=1LL<<60;const double INFF=1e100;const double eps=1e-8;const int mod=1000000007;const int NN=2005;const int MM=1000010;/* ****************** */LL dp[NN][NN];LL sum[NN];int s[NN][NN];int tol;string ans[NN];char s1[NN];void dfs(int l,int r,string ss){    if(l==r)    {        ans[l]=ss;        return;    }    dfs(l,s[l][r]-1,ss+'0');    dfs(s[l][r],r,ss+'1');}int main(){    int n,i,j,t,l,k;    while(scanf("%d",&n)!=EOF)    {        sum[0]=0;        for(i=1;i<=n;i++)        {            scanf("%d",&t);            sum[i]=sum[i-1]+t;        }        for(l=1;l<=n;l++)        {            for(i=1;i<=n+1-l;i++)            {                j=i+l-1;                if(l==1)dp[i][j]=0;                else if(l==2)                {                    s[i][j]=j;                    dp[i][j]=sum[j]-sum[i-1];                }                else                {                    dp[i][j]=INF;                    for(k=s[i][j-1];k<=s[i+1][j];k++)                    {                        LL temp=dp[i][k-1]+dp[k][j]+sum[j]-sum[i-1];                        if(temp<=dp[i][j])                        {                            dp[i][j]=temp;                            s[i][j]=k;                        }                    }                }            }        }        dfs(1,n,"");        for(i=1;i<=n;i++)        {            for(j=0;j<(int)ans[i].size();j++)                s1[j]=ans[i][j];            s1[j]='\0';            printf("%s\n",s1);         //   cout<<ans[i]<<endl;        }    }    return 0;}


0 0
原创粉丝点击