zoukankan      html  css  js  c++  java
  • pku2817 WordStack

    题意:给定N 个字符串,每个字符串长度为小于等于10 ,要求得到一个排列,s[i] 为str[i] 和str[i - 1] 通过移动,相同位置上相同字符的个数,求max(s[1] + s[2] + s[3] +...)
    分析:aaa 和 abc 的相同的字符数 为1
    abc 和 adc 相同的字符数为2
    cde 和 bfcde 相同的字符数为3
    N个总数只有10, 很容易就想到了状态压缩,我们用dp[j][i]表示以第一个串结尾, 状态为j时 最大的相同字符数, j 的二进制位上每一个位的0 或1 表示是否已选了第几个串
     
     
    pku2817
    #include<iostream>
    #include<algorithm>
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #include<iterator>
    
    using namespace std;
    
    const int N = 10 + 5;
    
    int dp[1 << N][N];
    char str[N][N];
    
    int getNum(int u, int v)
    {
        int ret = 0;
        int len1 = strlen(str[u]), len2 = strlen(str[v]);
        for(int i = 0; i < len1; ++i)
        {
            int tmp = i, num = 0;
            for(int j = 0; j < len2 && tmp < len1; ++j)
            {
                if(str[u][tmp] == str[v][j])
                {
                    ++num;
                }
                ++tmp;
            }
            ret = max(ret, num);
        }
        return ret;
    }
    
    int dist[N][N];
    
    int main()
    {
        int n;
        while(scanf("%d",&n) == 1)
        {
            if(n <= 0) break;
            memset(dp, -1, sizeof(dp));
            for(int i = 0; i < n; ++i)
            {
                scanf("%s",str[i]);
                dp[(1 << i)][i] = 0;
            }
            for(int i = 0; i < n; ++i)
                for(int j = 0; j < n; ++j)
                    dist[i][j] = getNum(i, j);
            for(int i = 0; i < n; ++i)
                for(int j = i + 1; j < n; ++j)
                {
                    int tmp = max(dist[i][j], dist[j][i]);
                    dist[i][j] = dist[j][i] = tmp;
                }
                //for(int i = 0; i < n; ++i)
                //{
                //    for(int j = 0; j < n; ++j)
                //        cout << dist[i][j] << ' ';
                //    cout << endl;
                //}
                //cout << (1 << n) - 1 << endl;
                for(int m = 1; m < n; ++m)
                {
                    for(int j = (1 << n) - 1; j >= 0; --j)
                    {
                        for(int k = 0; k < n; ++k)
                        {
                            if(dp[j][k] == -1) continue;
                            for(int i = 0; i < n; ++i)
                            {
                                if( i == k) continue;
                                if(j & ( 1 << i)) continue;
                                int nex = j | (1 << i);
                                //cout << nex << ' ' << j << endl;
                                dp[nex][i] = max(dp[nex][i], dp[j][k] + dist[k][i]);
                                //cout << dp[nex][i] << ' ' << dp[j][k] << ' ' << dist[k][i] << endl;
                                
                            }
                            
                        }
                    }
                }
                int ans = 0;
                for(int i = 0; i < n; ++i)
                {
                    ans = max(ans, dp[(1 << n) - 1][i]);
                }
                printf("%d\n", ans);
        }
    }

     时间是一样的,不过少了一层for, 将枚举状态j的for循环倒过来,类似01背包和完全背包的那个过程

    新版本
    #include<iostream>
    #include<algorithm>
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #include<iterator>
    
    using namespace std;
    
    const int N = 10 + 5;
    
    int dp[1 << N][N];
    char str[N][N];
    
    int getNum(int u, int v)
    {
        int ret = 0;
        int len1 = strlen(str[u]), len2 = strlen(str[v]);
        for(int i = 0; i < len1; ++i)
        {
            int tmp = i, num = 0;
            for(int j = 0; j < len2 && tmp < len1; ++j)
            {
                if(str[u][tmp] == str[v][j])
                {
                    ++num;
                }
                ++tmp;
            }
            ret = max(ret, num);
        }
        return ret;
    }
    
    int dist[N][N];
    
    int main()
    {
        int n;
        while(scanf("%d",&n) == 1)
        {
            if(n <= 0) break;
            memset(dp, -1, sizeof(dp));
            for(int i = 0; i < n; ++i)
            {
                scanf("%s",str[i]);
                dp[(1 << i)][i] = 0;
            }
            for(int i = 0; i < n; ++i)
                for(int j = 0; j < n; ++j)
                    dist[i][j] = getNum(i, j);
            for(int i = 0; i < n; ++i)
                for(int j = i + 1; j < n; ++j)
                {
                    int tmp = max(dist[i][j], dist[j][i]);
                    dist[i][j] = dist[j][i] = tmp;
                }
                //for(int m = 1; m < n; ++m)
                //{
                //    for(int j = (1 << n) - 1; j >= 0; --j)
                //    {
                //        for(int k = 0; k < n; ++k)
                //        {
                //            if(dp[j][k] == -1) continue;
                //            for(int i = 0; i < n; ++i)
                //            {
                //                if( i == k) continue;
                //                if(j & ( 1 << i)) continue;
                //                int nex = j | (1 << i);
                //                dp[nex][i] = max(dp[nex][i], dp[j][k] + dist[k][i]);
                //                
                //            }
                //            
                //        }
                //    }
                //}
                for(int j = 0; j <= (1 << n) - 1; ++j)
                {
                    for(int k = 0; k < n; ++k)
                    {
                        if(dp[j][k] == -1) continue;
                        for(int i = 0; i < n; ++i)
                        {
                            if( i == k) continue;
                            if(j & ( 1 << i)) continue;
                            int nex = j | (1 << i);
                            dp[nex][i] = max(dp[nex][i], dp[j][k] + dist[k][i]);
    
                        }
    
                    }
                }
                int ans = 0;
                for(int i = 0; i < n; ++i)
                {
                    ans = max(ans, dp[(1 << n) - 1][i]);
                }
                printf("%d\n", ans);
        }
    }
  • 相关阅读:
    nginx不支持pathinfo模式解决方法
    php只保留两位小数
    分享图文到QQ空间
    android 使用信鸽推送通知栏不显示推送的通知?
    Editetext获取焦点后让输入软键盘中出现搜索按键
    Android EditText的使用过程中遇到的问题
    在线根据现有apk生成指定id的推广apk (已过时)
    @Validated和@Valid区别
    idea快捷键使用总结
    大概
  • 原文地址:https://www.cnblogs.com/nanke/p/3002488.html
Copyright © 2011-2022 走看看