[POJ] 状态压缩DP专题

POJ3254 Corn Fields

POJ3254
状态压缩DP的入门题。纯粹的二维递推,还可以通过滚动数组优化,但这里并不需要。

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int M,N,f[13][1<<12];
int map[13];
int in()
 {
    char ch=getchar();
    while(ch!='1'&&ch!='0') ch=getchar();
    return ch-'0';
 }
bool check(int j,int k)
 {
    if((j&k)||(k&(k<<1))) return false;
    return true;
 }
int main()
 {
     cin >> M >> N;
     memset(f,0,sizeof(f));
     memset(map,0,sizeof(map));
     int Ans=0;
     for ( int i=1;i<=M;i++) {
        for(int j=1;j<=N;j++)
         map[i]=(map[i]<<1)+(!in());
}
     for ( int i=0;i<=(1<<N)-1;i++)
       if(check(map[1],i))
         f[1][i]=1;
     for ( int i=2;i<=M;i++)
       for ( unsigned int j=0;j<=(1<<N)-1;j++)
         if(check(map[i],j)){
           for ( unsigned int k=0;k<=(1<<N)-1;k++)
             {
                if((k&j)||check(map[i-1],k)==false) continue;
                f[i][j]+=f[i-1][k];
                f[i][j]%=100000000;
             }}
     for ( int i=0;i<=(1<<N)-1;i++)
      {
             Ans+=f[M][i];
             Ans%=100000000;
        }
     cout << Ans << endl;
     return 0;
 }

POJ1185 NOI2001 炮兵布阵

POJ1185

一道Debug了一天一夜的题目。

将炮兵的放法状压,离散掉。然后预处理出前两行的情况。随后进行递推,每次枚举该行,前一行和前两行的状态即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bitset>
using namespace std;
int f[101][70][70];
int N,M;
unsigned int list[2000],num[2000],cnt=0;
unsigned int map[100];
char in()
 {
    char ch=getchar(); 
    while(ch!='H'&&ch!='P') 
     ch=getchar();
    return ch;
 }
int main()
 { 
    unsigned int temp=0;
    cin >> N >> M;
    for ( unsigned int i=0;i<=(1<<M)-1;i++)
      if((i&(i<<1))==0&&(i&(i<<2))==0)
       {
           num[cnt]=0; 
           temp=i;
           while(temp)
            {
                num[cnt]+=temp&1;
                temp>>=1;
            }
           list[cnt++]=i;
      }
    for ( int i=0;i<=100;i++)
      for ( int j=0;j<=cnt;j++)
        for ( int k=0;k<=cnt;k++)
         f[i][j][k]=-1;
    for ( int i=1;i<=N;i++){
      temp=0;
        for ( int j=1;j<=M;j++)
         {
             temp<<=1;
             if(in()=='P')
               temp++;
          }
       map[i]=temp;
    } 
    for ( int j=0;j<cnt;j++)
        if(!((~map[1])&list[j]))
            f[1][j][0]=num[j];
    for ( int i=2;i<=N;i++){
      for ( int j=0;j<cnt;j++){
        if((~map[i])&list[j])
          continue;
        for ( int k=0;k<cnt;k++)
         if(!(((~map[i])|list[k])&list[j]))
          for( int l=0;l<cnt;l++)
           if(f[i-1][k][l]!=-1&&(!(list[l]&list[j]))){
            f[i][j][k]=max(f[i][j][k],f[i-1][k][l]+(int)num[j]); // j 为当前维度 , k为之前维度 
         }
     }
}
    int Ans=0;
    for ( int j=0;j<cnt;j++)
      for ( int k=0;k<cnt;k++)
        Ans=max(f[N][j][k],Ans);
    cout << Ans << endl;
    return 0;
 }

POJ2441 Arrange the bulls

POJ2441
与第一题较为相似,但是此处必须使用滚动数组来优化,(内存限制是65536KB),而且不需要取模。其他都是一些递推的套路,严格来说算不上动归。

#include <iostream>
#include <cstring>
#include <bitset>
using namespace std;
int f[2][1<<20];
int matrix[21];
int main()
 {
    int N,M;
    cin >> N >> M;
    int T1,T2;
    for ( int i=1;i<=N;i++)
     {
        cin >> T1;
        for ( int j=1;j<=T1;j++)
          {
              cin >> T2;
              matrix[T2]+=1<<i;
          }
     }
    memset(f,0,sizeof(f));
    f[0][0]=1;
    for ( int i=1;i<=N;i++){
       for ( int j=0;j<=(1<<M)-1;j++)
        if(f[(i-1)&1][j])
          for ( int k=1;k<=M;k++)
            if((matrix[k]&(1<<i))&&(j!=(j|(1<<(k-1)))))
              f[i&1][j|(1<<(k-1))]+=f[(i-1)&1][j];
       memset(f[(i-1)&1],0,sizeof(f[(i-1)&1]));
}
    int Ans=0;
    for ( int i=0;i<=(1<<M)-1;i++)
      Ans+=f[N&1][i];
    cout << Ans << endl;
    return 0;
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值