zoukankan      html  css  js  c++  java
  • hdu 4317 Unfair Nim (状态压缩DP) 【2012 MultiUniversity Training Contest 2】

    一道状态压缩DP,比赛时没时间仔细想了,赛后想了想转移那部分也有点糊里糊涂的,后来请教了一下yk同学,才肯定了一下那个状态表示,后来自己一边探索,一边敲码,一边调试,确认无误后得到1A。

    看到题很自然的想到从低位开始往高位处理,基本处理加的思路是:在本位上只有可能+1(由1变成0,由0变成1)或者+2(由0变成0,由1变成1,但是存在进位),基本的情况是本位只可能主动+1,如果+2则可能是后一位进位过来了的。

    基本状态是dp[i][j]:处理玩了第i位(第0~i位异或已经全为0),第i位有j堆需要想第i+1位进位。

    状态转移:由第i+1位本身的值,加上第i位至第i+1位的进位,会得到一串新的值,但是如果不是偶数个1的话,第i+1位的异或结果是不会为0的,并且第i+1位也是可以要有自己本身的状态的,所以要再枚举2^n种变化,只对能够得到异或结果为0的状态进行更新。

    更新的方法:

      最后第i+1位的结果是由第i+1位本身的值,第i位进位的值,以及枚举的第i+1位是否要变化+1的值,三个值一起决定的,第i+1位本身的值 异或 第i位进位的值,得到的是目前第i+1位的值,可以先预处理出目前的情况与那些变化相结合是可以得到合法状态的,继而跟新。将3个值相异或即可得到第i+1位剩下的结果,是偶数个1就是合法的结果。

      而也要知道第i+1位向第i+2位进位的结果,仔细观察后可以发现如果那三个值中某一位存在两个或两个以上的1时就会有对上一位的进位,而怎么顺利得到呢?这个就要仰慕一下severus大牛的指导,居然用到了《数电》里面的知识,F=ABC+AB¬C+A¬BC+¬ABC,化简之后就是得到的AB+(A^B)C,这样dp[i][]就可以由dp[i-1][]转化得到了。下面附代码:

    View Code
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define N 10
     6 #define inf (1<<30)
     7 #define see(x) cout<<#x<<":"<<x<<endl;
     8 using namespace std;
     9 const int maxn = 1<<N;
    10 bool cha[maxn][maxn];
    11 int dp[20][maxn];
    12 int num[20];
    13 int c[maxn];
    14 inline int cal(int x){        //取出X里2进制1的个数
    15     if(c[x]!=-1) return c[x];
    16     int y = x;
    17     x=(x & 0x55555555) + ((x >>1 ) & 0x55555555);
    18     x=(x & 0x33333333) + ((x >>2 ) & 0x33333333);
    19     x=(x & 0x0F0F0F0F) + ((x >>4 ) & 0x0F0F0F0F);
    20     x=(x & 0x00FF00FF) + ((x >>8 ) & 0x00FF00FF);
    21     x=(x & 0x0000FFFF) + ((x >>16) & 0x0000FFFF);
    22     return c[y]=x;
    23 }
    24 int a[N];
    25 int main(){
    26     int n, i, j, k, m, ans;
    27     memset(cha,0,sizeof(cha));
    28     memset(c,-1,sizeof(c));
    29     for(i=0;i<maxn;i++){
    30         for(j=0;j<maxn;j++){
    31             k = i^j;
    32             if((cal(k)&1)==0){
    33                 cha[i][j] = 1;
    34             }
    35         }
    36     }
    37     while(~scanf("%d",&n)){
    38         m = 0;
    39         memset(num,0,sizeof(num));
    40         for(i=0;i<n;i++){
    41             scanf("%d",&a[i]);
    42             for(k=0;a[i]>=(1<<k);k++){
    43                 if(a[i]&(1<<k)){
    44                     num[k] += (1<<i);
    45                 }
    46             }
    47             m = max(m,k);
    48         }
    49         for(i=0;i<=m;i++) for(j=0;j<(1<<n);j++){
    50             dp[i][j] = inf;
    51         }
    52         for(k=0;k<(1<<n);k++){
    53             if(cha[num[0]][k]){
    54                 dp[0][num[0]&k] = min(dp[0][num[0]&k],cal(k));
    55             }
    56         }
    57         for(i=1;i<=m;i++){
    58             for(j=0;j<(1<<n);j++){
    59                 for(k=0;k<(1<<n);k++){
    60                     if(cha[num[i]^j][k]){
    61                         dp[i][(num[i]&j)|((num[i]^j)&k)] = min(dp[i][(num[i]&j)|((num[i]^j)&k)],dp[i-1][j] + cal(k)*(1<<i));
    62                     }
    63                 }
    64             }
    65         }
    66         ans = dp[m][0];
    67         printf("%d\n",ans);
    68     }
    69     return 0;
    70 }
  • 相关阅读:
    Text box to accept only number
    两个经典的Oracle触发器示例
    ELK部署
    Win10+CentOS7双系统引导修复
    自定义多选框(checkbox)和单选框(radio)css样式
    js事件
    js数组与字符串处理 slice、splice、substring、substr、push、pop、shift、reverse、sort、join、split
    css入门基础
    cocos2dx基础篇(7) 触碰事件
    cocos2dx基础篇(6) 定时器schedule/update
  • 原文地址:https://www.cnblogs.com/celia01/p/2613919.html
Copyright © 2011-2022 走看看