状态dp
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
int legal[1<<20];
int num,a[21][21];
int dp[21][1<<20];
int n;
void init()
{
num=0;
for(int i=0;i<(1<<n);i++)
{
if(i&(i<<1) || i&(i>>1))
continue;
legal[++num]=i;
}
}
int get(int i,int j) // 第i行第j种状态下,本行可获取的值
{
int ans=0;
int tmp=legal[j];
int k=n;
while(tmp)
{
if(tmp&1)
ans+=a[i][k];
k--;
tmp/=2;
}
return ans;
}
int main()
{
init();
while(scanf("%d",&n)!=EOF)
{
init();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
for(int i=1;i<=n;i++)
a[0][i]=0;
int ans=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=num;j++)
{
int tmp=-0xfffffff;
for(int k=1;k<=num;k++)
{
if(legal[j]&legal[k])
continue;
tmp=max(tmp,dp[i-1][k]);
}
dp[i][j]=tmp+get(i,j);
ans=max(ans,dp[i][j]);
}
}
printf("%d\n",ans);
}
return 0;
}
2. poj 3254 Corn Fields
状态dp
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int mod=(1e8);
int dp[13][1<<12];
int legal[1<<12];
int num,pos[13];
int m,n;
void init()
{
num=0;
for(int i=0;i<(1<<n);i++)
{
if(i&(i<<1) || i&(i>>1))
continue;
legal[++num]=i;
}
}
int main()
{
int x;
while(scanf("%d%d",&m,&n)!=EOF)
{
init();
memset(dp,0,sizeof(dp));
for(int i=1;i<=m;i++)
{
pos[i]=0;
for(int j=1;j<=n;j++)
{
scanf("%d",&x);
if(x==0)
pos[i]|=1<<(n-j);
}
}
for(int i=1;i<=num;i++)
{
if(legal[i]&pos[1])
continue;
dp[1][i]=1;
}
for(int i=2;i<=m;i++)
for(int j=1;j<=num;j++)
{
if(pos[i]&legal[j])
continue;
for(int k=1;k<=num;k++)
{
if(pos[i-1]&legal[k])
continue;
if(legal[j]&legal[k])
continue;
dp[i][j]+=dp[i-1][k];
dp[i][j]%=mod;
}
}
int ans=0;
for(int i=1;i<=num;i++)
ans=(ans+dp[m][i])%mod;
printf("%d\n",ans);
}
return 0;
}
状态dp
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
int legal[61];
int dp[101][61][61];
int pos[101];
int a[101][11];
int num,n,m;
void init()
{
num=0;
for(int i=0;i<(1<<m);i++)
if( i&(i<<1) || i&(i<<2) || i&(i>>1) || i&(i>>2))
continue;
else
legal[++num]=i;
}
int get(int i,int j)
{
int ans=0;
int tmp=legal[j];
int k=m;
while(tmp)
{
if(tmp&1)
ans+=a[i][k];
k--;
tmp/=2;
}
return ans;
}
int main()
{
char s;
scanf("%d%d",&n,&m);
getchar();
init();
memset(a,0,sizeof(a));
memset(dp[1],0,sizeof(dp[1]));
for(int i=1;i<=n;i++)
{
pos[i]=0;
for(int j=1;j<=m;j++)
{
scanf("%c",&s);
if(s=='H')
{
pos[i]|=1<<(m-j);
}
else
a[i][j]=1;
}
getchar();
}
int ans=0;
/// dp[i][j][k] 表示当前第i行状态为j,第i-1行状态为k的方案数
//预处理第一行
for(int i=1;i<=num;i++)
{
if(pos[1]&legal[i])
continue;
dp[1][i][1]=get(1,i);
ans=max(ans,dp[1][i][1]);
}
// 预处理第二行
for(int i=1;i<=num;i++)
{
if(pos[2]&legal[i])
continue;
for(int j=1;j<=num;j++)
{
if(pos[1]&legal[j])
continue;
if(legal[i]&legal[j])
continue;
dp[2][i][j]=dp[1][j][1]+get(2,i);
ans=max(ans,dp[2][i][j]);
}
}
for(int i=3;i<=n;i++)
{
for(int j=1;j<=num;j++) // 当前行的状态
{
if(pos[i]&legal[j])
continue;
for(int k=1;k<=num;k++) // 前一行的状态
{
if(legal[j]&legal[k])
continue;
if(pos[i-1]&legal[k])
continue;
int tmp=-1;
for(int l=1;l<=num;l++)
{
if(legal[l]&pos[i-2])
continue;
if(legal[l]&legal[k])
continue;
if(legal[l]&legal[j])
continue;
tmp=max(tmp,dp[i-1][k][l]);
}
dp[i][j][k]=tmp+get(i,j);
ans=max(ans,dp[i][j][k]);
}
}
}
printf("%d\n",ans);
return 0;
}
4.light oj 1244 - Tiles
状态压缩,矩阵加速
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
#define mod 10007
struct Matrix
{
long long m[5][5];
}E,D,T;
void init()
{
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
{
E.m[i][j]=(i==j);
D.m[i][j]=0;
}
for(int i=1;i<=4;i++)
D.m[1][i]=1;
D.m[2][1]=1;
D.m[3][2]=D.m[3][4]=1;
D.m[4][2]=D.m[4][3]=1;
T.m[1][1]=T.m[2][1]=1;
T.m[3][1]=T.m[4][1]=0;
}
Matrix Multi(Matrix A,Matrix B)
{
Matrix ans;
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
{
ans.m[i][j]=0;
for(int k=1;k<=4;k++)
ans.m[i][j]=(ans.m[i][j]+A.m[i][k]*B.m[k][j])%mod;
}
return ans;
}
Matrix Pow(Matrix A,long long k)
{
Matrix ans=E;
while(k)
{
if(k&1)
{
k--;
ans=Multi(ans,A);
}
else
{
k/=2;
A=Multi(A,A);
}
}
return ans;
}
int main()
{
int t;
long long n;
scanf("%d",&t);
init();
for(int cases=1;cases<=t;cases++)
{
scanf("%lld",&n);
Matrix ans=Pow(D,n-1);
ans=Multi(ans,T);
printf("Case %d: %lld\n",cases,ans.m[1][1]);
}
return 0;
}
5. Tri Tiling
状态dp
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
long long dp[31][8];
int main()
{
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(int i=1;i<=30;i++)
{
dp[i][0]=dp[i-1][1]+dp[i-1][4]+dp[i-1][7];
dp[i][1]=dp[i-1][6]+dp[i-1][0];
dp[i][2]=dp[i-1][5];
dp[i][3]=dp[i-1][4];
dp[i][4]=dp[i-1][0]+dp[i-1][3];
dp[i][5]=dp[i-1][2];
dp[i][6]=dp[i-1][1];
dp[i][7]=dp[i-1][0];
}
int n;
while(scanf("%d",&n)!=EOF)
{
if(n<0)
break;
printf("%lld\n",dp[n][0]);
}
return 0;
}
6. poj 2411 Mondriaan's Dream
棋盘覆盖
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;
LL dp[12][1<<11];
// 设横着放的为11,竖着放的01
// 那么对于每行,一定不存在连续奇数的1
// 每两行不存在竖行连续为00
int m,n,mx;
bool ok1(int i)
{
//
int bits=0;
while(i)
{
if(i&1)
bits++;
else
{
if(bits&1)
return false;
bits=0;
}
i/=2;
}
if(bits&1)
return false;
return true;
}
bool ok2(int a,int b)
{
if((a|b)!=mx)
return false;
return ok1(a&b);
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
if(m==n&&m==0)
break;
if((m*n)&1)
printf("0\n");
else
{
if(m<n)
swap(m,n);
mx=(1<<m)-1;
memset(dp,0,sizeof(dp));
for(int i=0;i<(1<<m);i++)
if(ok1(i))
dp[1][i]=1;
for(int i=2;i<=n;i++)
for(int j=0;j<(1<<m);j++)
for(int k=0;k<(1<<m);k++)
if(ok2(j,k))
dp[i][j]+=dp[i-1][k];
printf("%I64d\n",dp[n][(1<<m)-1]);
}
}
return 0;
}
7. hdu 4539 郑厂长系列故事——排兵布阵
跟炮兵阵地一样,为了节省内存,用了滚动数组(上次看小萌用了这个)。
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
int legal[170];
int dp[2][170][170];
int a[101][11];
int num,n,m;
int pos[101];
void init()
{
num=0;
for(int i=0;i<(1<<m);i++)
{
if(i&(i<<2) || i&(i>>2))
continue;
legal[++num]=i;
}
}
int get(int i,int j)
{
int tmp=legal[j];
int k=m;
int ans=0;
while(tmp)
{
if(tmp&1)
{
ans+=a[i][k];
}
k--;
tmp/=2;
}
return ans;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
memset(a,0,sizeof(a));
//cout<<num<<endl;
for(int i=1;i<=n;i++)
{
pos[i]=0;
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
if(a[i][j]==0)
pos[i]|=(1<<(m-j));
}
//cout<<pos[i]<<endl;
}
int ans=0;
memset(dp,0,sizeof(dp));
for(int i=1;i<=num;i++)
{
if(pos[1]&legal[i])
continue;
dp[1][i][1]=get(1,i);
ans=max(ans,dp[1][i][1]);
}
memcpy(dp[0],dp[1],sizeof(dp[1]));
memset(dp[1],0,sizeof(dp[1]));
for(int i=1;i<=num;i++)
{
if(pos[2]&legal[i])
continue;
for(int j=1;j<=num;j++)
{
if(pos[1]&legal[j])
continue;
if((legal[j]<<1)&legal[i] || (legal[i]<<1)&legal[j])
continue;
dp[1][i][j]=dp[0][j][1]+get(2,i);
ans=max(ans,dp[1][i][j]);
}
}
for(int i=3;i<=n;i++)
{
memcpy(dp[0],dp[1],sizeof(dp[0]));
memset(dp[1],0,sizeof(dp[1]));
for(int j=1;j<=num;j++)
{
if(pos[i]&legal[j])
continue;
for(int k=1;k<=num;k++)
{
if(legal[k]&pos[i-1])
continue;
if((legal[j]<<1)&legal[k] || (legal[k]<<1)&legal[j])
continue;
int tmp=-1;
for(int l=1;l<=num;l++)
{
if(legal[l]&pos[i-2])
continue;
if(legal[l]&legal[j])
continue;
if((legal[l]<<1)&legal[k] || (legal[k]<<1)&legal[l])
continue;
tmp=max(tmp,dp[0][k][l]);
}
dp[1][j][k]=tmp+get(i,j);
ans=max(ans,dp[1][j][k]);
}
}
}
printf("%d\n",ans);
}
return 0;
}
8. nyoj 492 King
状态dp
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
int legal[150];
long long dp[2][150][101];
int num;
int n,k;
void init()
{
num=0;
for(int i=0;i<(1<<n);i++)
{
if(i&(i<<1) || i&(i>>1))
continue;
legal[++num]=i;
}
}
int get(int i)
{
int tmp=legal[i];
int ans=0;
while(tmp)
{
if(tmp&1)
ans++;
tmp/=2;
}
return ans;
}
int main()
{
while(scanf("%d%d",&n,&k)!=EOF)
{
init();
//cout<<num<<endl;
memset(dp,0,sizeof(dp));
dp[1][1][0]=1;
for(int i=1;i<=n;i++)
{
memcpy(dp[0],dp[1],sizeof(dp[0]));
memset(dp[1],0,sizeof(dp[1]));
for(int j=1;j<=num;j++)
{
for(int l=get(j);l<=k;l++)
{
for(int p=1;p<=num;p++)
{
if(legal[p]&legal[j])
continue;
if((legal[p]<<1)&legal[j])
continue;
if((legal[p]>>1)&legal[j])
continue;
dp[1][j][l]+=dp[0][p][l-get(j)];
}
}
}
}
long long ans=0;
for(int i=1;i<=num;i++)
ans+=dp[1][i][k];
printf("%lld\n",ans);
}
return 0;
}
9. poj 3311 Hie with the Pie
floyd + 状态dp
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
int dp[1<<11][12];
int cnt[12][12];
int main()
{
int n;
while(scanf("%d",&n),n!=0)
{
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
scanf("%d",&cnt[i][j]);
for(int k=0;k<=n;k++)
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
cnt[i][j]=min(cnt[i][j],cnt[i][k]+cnt[k][j]);
memset(dp,0x3f,sizeof(dp));
int ans=dp[0][0];
for(int state=0;state<(1<<n);state++)
{
for(int i=1;i<=n;i++)
{
if(state&(1<<(i-1)))
{
if(state==(1<<(i-1)))
{
dp[state][i]=cnt[0][i];
continue;
}
for(int j=1;j<=n;j++)
{
if(i==j)
continue;
if((1<<(j-1))&state)
dp[state][i]=min(dp[state][i],dp[state&~(1<<(i-1))][j]+cnt[j][i]);
}
}
}
}
for(int i=1;i<=n;i++)
ans=min(ans,dp[(1<<n)-1][i]+cnt[i][0]);
printf("%d\n",ans);
}
return 0;
}
或者用全排列水过
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
int cnt[12][12];
int path[12];
int main()
{
int n;
while(scanf("%d",&n),n!=0)
{
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
scanf("%d",&cnt[i][j]);
for(int k=0;k<=n;k++)
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
cnt[i][j]=min(cnt[i][j],cnt[i][k]+cnt[k][j]);
for(int i=1;i<=n;i++)
path[i]=i;
int ans=0x7fffffff;
int tmp;
do
{
tmp=cnt[0][path[1]];
tmp+=cnt[path[n]][0];
for(int i=1;i<n;i++)
tmp+=cnt[path[i]][path[i+1]];
ans=min(ans,tmp);
}while(next_permutation(path+1,path+n+1));
printf("%d\n",ans);
}
return 0;
}