ZOJ 2561 Order-Preserving Codes DP 四邊形優化

題目大意:給你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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章