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 炮兵布阵
一道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;
}