zoukankan      html  css  js  c++  java
  • HDU5691 状态压缩dp

      附上题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5691

       

    Problem Description
    度度熊是他同时代中最伟大的数学家,一切数字都要听命于他。现在,又到了度度熊和他的数字仆人们玩排排坐游戏的时候了。游戏的规则十分简单,参与游戏的N个整数将会做成一排,他们将通过不断交换自己的位置,最终达到所有相邻两数乘积的和最大的目的,参与游戏的数字有整数也有负数。度度熊为了在他的数字仆人面前展现他的权威,他规定某些数字只能在坐固定的位置上,没有被度度熊限制的数字则可以自由地交换位置。
     
    Input
    第一行一个整数T,表示T组数据。
    每组测试数据将以如下格式从标准输入读入:

    N

    a1p1

    a2p2



    aNPN

    第一行,整数 N(1N16),代表参与游戏的整数的个数。

    从第二行到第 (N+1) 行,每行两个整数,ai(10000ai10000)pi(pi=1 或 0pi<N),以空格分割。ai代表参与游戏的数字的值,pi代表度度熊为该数字指定的位置,如果pi=1,代表该数字的位置不被限制。度度熊保证不会为两个数字指定相同的位置。
     
    Output
    第一行输出:"Case #i:"。i代表第i组测试数据。

    第二行输出数字重新排列后最大的所有相邻两数乘积的和,即max{a1a2+a2a3+......+aN1aN}
     
    分析:由于N很小, 所以我们考虑使用状态压缩的dp解决这个问题, 定义dp[st][i]为以a[i]结尾已经用了st的最大值。 具体状态转移见代码, 为了方便, 我们在这个序列之前加了一个数0。 代码如下:
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    
    const int maxn = 20;
    int N;
    int a[20], pos[20];
    int dp[(1<<17)][maxn];
    
    int main() {
        int T;
        scanf("%d", &T);
        int kase = 0;
        while(T--) {
            scanf("%d", &N);
            for(int i=1; i<=N; i++){
                scanf("%d%d", &a[i], &pos[i]);
            }
            a[0] = 0;
            for(int st=0; st<(1<<N); st++)
            for(int i=0; i<=N; i++) dp[st][i] = -0x3f3f3f3f;
            dp[0][0] = 0;
            //printf("%d
    ", dp[0][1]);
            int res = -0x3f3f3f3f;
            for(int st=0; st<(1<<N); st++)
            for(int i=0; i<=N; i++) {
                if(dp[st][i] == -0x3f3f3f3f) continue;
                if(st == (1<<N)-1) res = max(res, dp[st][i]);
                for(int j=1; j<=N; j++) {    //a[i] a[j]
                    if((st>>(j-1))&1) continue;
                    if(pos[j] == -1) {
                        dp[st|(1<<(j-1))][j] = max(dp[st|(1<<(j-1))][j], dp[st][i] + a[i]*a[j]);
                    }else{
                        int cnt = 0;
                        for(int t=0; t<N; t++) if((st>>t)&1) cnt++;
                        if(cnt != pos[j]) continue;
                        dp[st|(1<<(j-1))][j] = max(dp[st|(1<<(j-1))][j], dp[st][i] + a[i]*a[j]);
                    }
                }
            }
            printf("Case #%d:
    ", ++kase);
            printf("%d
    ", res);
        }
        return 0;
    }
  • 相关阅读:
    sqlite3.6.10的vs2005 编译错误
    .NET网络编程学习(二)
    Lucene的使用(一)
    .NET网络编程学习(三)
    深入学习Heritrix解析Frontier(链接工厂)
    .NET网络编程学习(一)
    Subversion的Windows服务配置
    深入学习Heritrix解析处理器(Processor)
    log4net的使用
    深入学习Heritrix解析CrawlController
  • 原文地址:https://www.cnblogs.com/xingxing1024/p/5543407.html
Copyright © 2011-2022 走看看