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

    1:POJ 炮兵阵地

      预先处理好情况,然后又类似格子取数的状压。

    我们用DP[I][J][K]表示处理第I个格子,I-1格子的状态为J,I-2的格子为K,然后转移

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<algorithm>
     4 #include<math.h>
     5 #include<vector>
     6 using namespace std;
     7 char s[123][123];
     8 int n,m,dp[123][123][123];
     9 int ok[12345],mp[123][123];
    10 vector<int>v[123];
    11 int t;
    12 int cal(int x)//计算能放的数量
    13 {
    14     int ans=0;
    15     while (x){
    16         if (x&1) ans++;
    17         x/=2;
    18     }
    19     return ans;
    20 }
    21 
    22 void init()//预处理
    23 {
    24     t=0;
    25     for (int i=0;i<(1<<m);i++)
    26     {
    27         if ((i<<1)&i) continue;
    28         if ((i<<2)&i) continue;
    29         ok[t++]=i;
    30     }
    31     for (int i=0;i<n;i++)
    32     {
    33         v[i].clear();
    34         for (int j=0;j<t;j++)
    35         {
    36             int flag=1;
    37             int top=0;
    38             for (int k=0;k<m;k++)
    39                 if (s[i][k]=='H'&&(ok[j]&(1<<k)))
    40                 {
    41                 flag=0;
    42                 break;
    43                 }
    44             if (flag) v[i].push_back(ok[j]);
    45       }
    46     }
    47 }
    48 
    49 int main()
    50 {
    51     while (scanf("%d%d",&n,&m)!=EOF)
    52     {
    53         for (int i=0;i<n;i++) scanf("%s",s[i]);
    54         init();
    55         memset(dp,-1,sizeof(dp));
    56         for (int i=0;i<v[0].size();i++) dp[0][i][0]=cal(v[0][i]);//处理1,2行的情况
    57         for (int i=0;i<v[0].size();i++)
    58             for (int j=0;j<v[1].size();j++)
    59             if (!(v[0][i]&v[1][j])&&dp[0][i][0]!=-1)  dp[1][j][i]=dp[0][i][0]+cal(v[1][j]);
    60 
    61         for (int i=2;i<n;i++)
    62             for (int j=0;j<v[i].size();j++)
    63               for (int k=0;k<v[i-1].size();k++){
    64                 if (v[i][j]&v[i-1][k]) continue;
    65                   for (int p=0;p<v[i-2].size();p++)
    66                     if (dp[i-1][k][p]!=-1&&(v[i][j]&v[i-2][p])==0)
    67                     dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][p]+cal(v[i][j]));
    68            }
    69         int ans=0;
    70         for (int i=0;i<t;i++)
    71         for (int j=0;j<t;j++)
    72         ans=max(ans,dp[n-1][i][j]);
    73     printf("%d ",ans);
    74     }
    75   return 0;
    76 }

    2:POJ 3254 

     

    Corn Fields

     入门提: 1 #include<stdio.h>

     2 #include<string.h>
     3 #include<math.h>
     4 #include<vector>
     5 #include<algorithm>
     6 using namespace std;
     7 int dp[22][1<<13];
     8 int mp[20][20];
     9 vector<int> v[2134];
    10 const int M=100000000;
    11 int n,m;
    12 int t;
    13 int state[123456];
    14 
    15 void init()
    16 {
    17     t=0;
    18     for (int i=0;i<n;i++)
    19       for (int j=0;j<m;j++) scanf("%d",&mp[i][j]);
    20     for (int i=0;i<(1<<m);i++)
    21     {
    22         if (i&(i>>1)) continue;
    23         if (i&(i<<1)) continue;
    24         state[++t]=i;
    25         }
    26     for (int i=0;i<n;i++)
    27     {
    28         v[i].clear();
    29         for (int j=1;j<=t;j++){
    30              int flag=1;
    31         for (int p=0;p<m;p++)
    32         if (mp[i][p]==0&&(state[j]&(1<<p)))
    33         {
    34             flag=0;
    35             break;
    36         }
    37         if (flag) v[i].push_back(state[j]);
    38       }
    39     }
    40 }
    41 
    42 int main()
    43 {
    44     while (scanf("%d%d",&n,&m)!=EOF)
    45     {
    46          init();
    47          memset(dp,0,sizeof(dp));
    48          for (int i=0;i<v[0].size();i++) dp[0][i]=1;
    49          for (int i=1;i<n;i++)
    50          for (int j=0;j<v[i].size();j++){
    51                 int now=v[i][j];
    52                 for (int k=0;k<v[i-1].size();k++)
    53                 if (!(now&(v[i-1][k])))
    54                    {dp[i][j]+=dp[i-1][k];
    55                              dp[i][j]%=M;
    56                           }
    57     }
    58     int ans=0;
    59     for (int i=0;i<v[n-1].size();i++){
    60         ans+=dp[n-1][i];
    61         ans%=M;
    62     }
    63     printf("%d ",ans);
    64   }
    65   return 0;
    66 }        
                                                                                                                                                             
    POJ:3311
    哈密顿回路:N只有10,先求出任意一点的回路,难后状态压缩:
    #include <iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<stdlib.h>
    #include<vector>
    #include<cmath>
    #include<queue>
    #include<set>
    #include<list>
    #define inf 123456789
    int n;
    int mp[12][12],dp[1<<12][12];
    using namespace std;
    int main()
    {
        while (scanf("%d",&n)!=EOF)
        {
            if (n==0) break;
            for (int i=0;i<=n;i++)
                for (int j=0;j<=n;j++)
                  scanf("%d",&mp[i][j]);
            for (int k=0;k<=n;k++)
                for (int i=0;i<=n;i++)
                 for (int j=0;j<=n;j++)
                  if (mp[i][j]>mp[i][k]+mp[k][j])
                   mp[i][j]=mp[i][k]+mp[k][j];
    
            for (int i=0;i<(1<<n);i++)
                for (int j=1;j<=n;j++)
                 if (i==(1<<(j-1))) dp[i][j]=mp[0][j];
              else if (i&(1<<(j-1)))
             {
                dp[i][j]=inf;
                for (int k=1;k<=n;k++)
                if (k!=j&&(i&(1<<(k-1))))
                dp[i][j]=min(dp[i][j],dp[(1<<(j-1))^i][k]+mp[k][j]);
              }
            int ans=inf;
            for (int i=1;i<=n;i++)
                ans=min(ans,dp[(1<<n)-1][i]+mp[i][0]);
          printf("%d
    ",ans);
        }
        return 0;
    }
    还有一种暴力方法,同时先预先求出点与点之间的最短路,然后求出全排列,再暴力枚举。
    #include <iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<stdlib.h>
    #include<vector>
    #include<cmath>
    #include<queue>
    #include<set>
    #include<list>
    #define inf 123456789
    int n;
    int mp[12][12],dp[1<<12][12];
    int a[12];
    using namespace std;
    int main()
    {
        while (scanf("%d",&n)!=EOF)
        {
            if (n==0) break;
            for (int i=0;i<=n;i++)
                for (int j=0;j<=n;j++)
                  scanf("%d",&mp[i][j]);
            for (int k=0;k<=n;k++)
                for (int i=0;i<=n;i++)
                 for (int j=0;j<=n;j++)
                  if (mp[i][j]>mp[i][k]+mp[k][j])
                   mp[i][j]=mp[i][k]+mp[k][j];
              int ans=inf;
           for (int i=1;i<=n;i++) a[i]=i;
           do
           {
                   int k=0;
                   int t=0;
                for (int i=1;i<=n;i++)
                k+=mp[t][a[i]],t=a[i];
                k+=mp[t][0];
             ans=min(ans,k);
           }while (next_permutation(a+1,a+n+1));
          printf("%d
    ",ans);
        }
        return 0;
    }
    

    hdu 3001:

    一辈子看错题:注意一个城市可以走两次

    还有重边。

    三进制表示很神奇

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 #include<set>
    10 #include<list>
    11 #define inf 0x3f3f3f3f
    12 typedef long long ll;
    13 using namespace std;
    14 int state[12];
    15 int vis[123456][12];
    16 int dp[123456][13];
    17 int mp[13][13];
    18 int n,m;
    19 void init()
    20 {
    21          state[0]=1;
    22          for (int i=1;i<=10;i++)
    23          state[i]=state[i-1]*3;
    24      for (int i=0;i<=state[10];i++)
    25      {
    26         int tmp=i;
    27         for (int j=0;j<=10;j++){
    28             vis[i][j]=tmp%3;
    29             tmp/=3;
    30             }
    31      }
    32 }
    33 
    34 int main()
    35 {
    36       init();
    37       while (scanf("%d%d",&n,&m)!=EOF)
    38         {
    39          memset(dp,inf,sizeof(dp));
    40          memset(mp,inf,sizeof(mp));
    41          for (int i=0;i<n;i++) dp[state[i]][i]=0;
    42          while (m--)
    43          {
    44             int u,v,c;
    45             scanf("%d%d%d",&u,&v,&c);
    46             u--;
    47             v--;
    48             mp[u][v]=mp[v][u]=min(mp[u][v],c);
    49          }
    50             int ans=inf;
    51             for (int i=0;i<state[n];i++){
    52             int flag=1;
    53             for (int j=0;j<n;j++){
    54             if (vis[i][j]==0) flag=0;
    55             if (dp[i][j]==inf) continue;
    56             for (int k=0;k<n;k++)
    57             if (k!=j) {
    58             if (vis[i][k]>=2||mp[j][k]==inf) continue;
    59             dp[i+state[k]][k]=min(dp[i+state[k]][k],dp[i][j]+mp[j][k]);
    60             }
    61           }
    62          if (flag)
    63              for (int j=0;j<n;j++) ans=min(ans,dp[i][j]);
    64         }
    65         if (ans==inf) ans=-1;
    66         printf("%d
    ",ans);
    67     }
    68     return 0;
    69 }
    View Code

      

    POJ2411;
     求N*M能放多少1*2的格子,虽然可以用二进制表示,但是转移方程状态又是另外一种写法
    参考:http://blog.csdn.net/shiwei408/article/details/8821853
         http://www.2cto.com/kf/201208/146894.html
    这里解释了转移方程的写法。
  • 相关阅读:
    new对象数组时的内存布局
    写程序取自己进程的AEP
    类虚函数表原理实现分析(当我们将虚表地址[n]中的函数替换,那么虚函数的实现就由我们来控制了)
    测试 __try, __finally, __except(被__finally捕获的异常, 还会被上一级的__except捕获。反之不行)
    围观M$的new
    将258.369 double值转为内存表示(科学计数法)
    Broadcast Reveiver作用
    DEBUG模式下, 内存中的变量地址分析
    不包含SDK头文件, 补全API定义
    俄罗斯方块SDK版
  • 原文地址:https://www.cnblogs.com/forgot93/p/3869304.html
Copyright © 2011-2022 走看看