zoukankan      html  css  js  c++  java
  • HDU3828 A + B problem

    HDU3828 A + B problem

    Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 125536/65536 K (Java/Others)
    Total Submission(s): 544    Accepted Submission(s): 116


    Problem Description
    QQ and OO always play the game of A + B. QQ gives tow decimal number A and B, and OO answers the sum at once. But to do the same things too often is boring. So, today they are fed up with the easy game, and they come up with new rules of the game.
    Rule1: When add A and B we use the binary system string of A and B.
    Rule2: We can overlap the same suffix of A and prefix of B.
    Rule3: If the binary system string of B is a substring of A we can use A to overlap B.

    To make the problem more interesting, QQ gives n numbers, OO should use every one of them and every one once, then give the smallest of the sum. Now OO have no time to do it and need your help. You're a talented programmer you can do it.
     
    Input
    There are several tests, every test begin with n followed with n (0 < n < 16) lines, each line is a decimal number ai(0 < ai < 2^64) as described above.
    Process until EOF.
     
    Output
    For each test you should print the smallest answer per line, maybe the answer is large you should mod 1000000009.
     
    Sample Input
    2
    5
    3
    3
    245
    351
    107
    Sample Output
    11
    3935
    ********************************************************************
    题目大意:有n个数要求连起来。首先这些数字先都写成二进制,然后,对于两个数a和b,如果二进制中a是b的子串,那么连起来的话就是b了,即b把a覆盖了。如果a和b不是子串关系,如果二进制串中,a的末尾几个数和b的初始几个数相同,那么a和b连起来就成了a和b连着写,但是中间一样的东西只写一遍。现在要把n个数连起来,求连起来之后的串转化成10进制最小的值。
    解体思路:对于一个二进制串转化成十进制最小有两个条件:1,这个串的长度最小;2,这个串是最小字典序。
    原本想了很多dp思路,但是碍于庞大的数据量,或者是数组不好开,或者是dp内部不知道放什么,实在是没法子了,参考了一下网上的资料,唉,不爽啊,这道dp题又算是白做了。
    网上说,dp是二维dp,第一维存的是状态,第二维存的是总字符串最左边开始的那个字符串的序号,dp里面存的是当前最短的总字符串长度值。我就纳闷了,如果这个dp只是求把这几个二进制串连在一起的最短的值,那很好理解,但现在要求的是最小的字典序的串,这个状态怎么能保证最优呢?然而是我才疏学浅了,这样的确可以求出最优值。dp首先把最短的字符串的长度算出来了,然后我们由最后的dp再倒着往前推,我们按字段序最小往前推,这样就能算出最小值!太犀利了。
    还有一点,字典序最小往前推的时候并不是数字的字典序,而是数字的部分字典序,我想我讲的很乱,唉,语文没学好,就这样吧。
    #include <stdio.h>
    #include <string.h>
    #include <string>
    #include <stdlib.h>
    #include <vector>
    #include <math.h>
    #include <algorithm>
    #include <iostream>
    #define N 16
    #define M 1<<16
    #define MS 1000000009
    #define LL long long
    using namespace std;
    
    int n,goal;
    string str[N];
    LL da[N];
    int gra[N][N],mark[N];
    int slen[N];
    int dp[M][N];
    LL ans;
    
    void ini(void)
    {
        goal=(1<<n)-1;
        for(int i=0;i<n;i++)
            str[i].clear();
        for(int i=0;i<n;i++)
        {
            LL k=da[i];
            while(k)
            {
                str[i].push_back((k&1)+'0');
                k=k>>1;
            }
            int j=str[i].size();
            string tempstr;
            while(j--)
                tempstr.push_back(str[i][j]);
            str[i]=tempstr;
        }
        sort(str,str+n);
        for(int i=0;i<n;i++)
            slen[i]=str[i].size();
        memset(mark,0,sizeof(mark));
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                if(i!=j&&slen[i]>slen[j])
                    for(int k1=0;k1<slen[i]-slen[j]+1;k1++)
                    {
                        int flag=0;
                        for(int k2=0;k2<slen[j];k2++)
                            if(str[i][k1+k2]!=str[j][k2])
                            {
                                flag=1;
                                break;
                            }
                        if(flag==0)
                        {
                            if(!mark[j])
                            {
                                mark[j]=1;
                                goal-=(1<<j);
                            }
                            break;
                        }
                    }
        for(int i=0;i<n-1;i++)
            for(int j=i+1;j<n;j++)
                if(!mark[i]&&!mark[j]&&str[i]==str[j])
                    mark[j]=1,goal-=(1<<j);
        memset(gra,0,sizeof(gra));
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                if(!mark[i]&&!mark[j]&&i!=j)
                    for(int k=0;k<slen[i];k++)
                    {
                        int flag=0;
                        for(int u=0;u+k<slen[i];u++)
                            if(str[i][k+u]!=str[j][u])
                            {
                                flag=1;
                                break;
                            }
                        if(!flag)
                        {
                            gra[i][j]=slen[i]-k;
                            break;
                        }
                    }
    }
    
    void dfs(int s,int p)
    {
        if(~dp[s][p])return ;
        if(s==(1<<p))
        {
            dp[s][p]=slen[p];
            return ;
        }
        int minn=0x3f3f3f3f;
        int t=s-(1<<p);
        for(int i=0;i<n;i++)
            if(!mark[i]&&i!=p&&(s&(1<<i)))
            {
                dfs(t,i);
                minn=min(minn,dp[t][i]-gra[p][i]);
            }
        dp[s][p]=minn+slen[p];
    }
    
    void rans(int s,int p,int e)
    {
        for(int i=e;i<slen[p];i++)
            ans=(ans*2+str[p][i]-'0')%MS;
        if(s==(1<<p))return ;
        int t=s-(1<<p);
        int k=-1;
        string a;
        for(int i=0;i<n;i++)
            if(!mark[i]&&(s&(1<<i))&&dp[t][i]-gra[p][i]+slen[p]==dp[s][p])
            {
                string b(str[i],gra[p][i],slen[p]-gra[p][i]);
                if(k==-1||a>b)
                    a=b,k=i;
            }
        rans(t,k,gra[p][k]);
    }
    
    void re(void)
    {
        for(int i=0;i<n;i++)
            scanf("%lld",&da[i]);
    }
    
    void run(void)
    {
        ini();
        memset(dp,-1,sizeof(dp));
        for(int i=0;i<n;i++)
            if(!mark[i])
                dfs(goal,i);
        int p,minn=0x3f3f3f3f;
        for(int i=0;i<n;i++)
            if(!mark[i]&&dp[goal][i]<minn)
                p=i,minn=dp[goal][i];
        ans=0;
        rans(goal,p,0);
        printf("%lld\n",ans);
    }
    
    int main()
    {
        while(scanf("%d",&n)!=EOF)
        {
            re();
            run();
        }
        return 0;
    }
    
  • 相关阅读:
    vm中花屏的最直接解决办法
    【转】SQL SERVER中一些常见性能问题的总结
    好不容易把Head First Design Patterns下下来了,与大家分享一下
    没想到单位的bt下载的速度可以到这么快,满意了
    买了张水货的1Gsd卡
    商业缩略语汇总
    一些个人收集的书籍恢复下载
    sourceforge.net 是不是被封了?
    2009年我大学毕业了,我工作了,总结成长中的我的2009年 Fred
    Web Service的传输协议
  • 原文地址:https://www.cnblogs.com/Fatedayt/p/2266818.html
Copyright © 2011-2022 走看看