题目描述 https://loj.ac/problem/10172
看完题目,很清楚的想到这道题用状压DP来做,只不过这道题是个三进制的,做题过程中须注意转换。
下面简单说一下算法
1. 用0 1 2 来代替题目中的1 2 3这样比较方便,将第k行以三进制数存入。先用一个数组存所以可行的状态,若第k行的状态不在数组里,直接输出0.
2. 这道题中已经给出了一行的状态,所以搜到k行要特判
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int modd=1e6;
int ans[10005][2187],st[2187],f,an,n,m,tot,pp;
int jud(int x)
{
int tp=0x3f;
for(int i=1;i<=m;i++)
{
if(tp==x%3) return 0;
tp=x%3,x/=3;
}
return 1;
}
int ff(int x,int y)
{
for(int i=1;i<=m;i++)
{
if(x%3==y%3) return 0;
x/=3,y/=3;
}
return 1;
}
int main()
{ int k;
scanf("%d%d%d",&n,&m,&k);
int cnt=1;
for(int i=1;i<=m;i++)
{
int a;
scanf("%d",&a);
f=f*3+a-1;
cnt=cnt*3;
}
for(int i=0;i<cnt;i++)
if(jud(i)==1) st[++tot]=i;
for(int i=1;i<=tot;i++)
if(f==st[i])
{
pp=i; break;
}
if(pp==0)
{
cout<<0; return 0;
}//ans[i][j]表示第i行 状态为j的方案数
for(int i=1;i<=n;i++)
{
if(i==k)
{
if(i==1) ans[i][pp]=1;
else
for(int j=1;j<=tot;j++)//枚举上一行状态
if(ff(st[pp],st[j])==1)
ans[i][pp]=(ans[i][pp]+ans[i-1][j])%modd;
}
else
for(int j=1;j<=tot;j++)//枚举本行状态
{
if(i==1) ans[i][j]=1;
else
for(int p=1;p<=tot;p++)//枚举上一行状态
if(ff(st[j],st[p])==1)
ans[i][j]=(ans[i][j]+ans[i-1][p])%modd;
}
}
for(int i=1;i<=tot;i++)
an=(an+ans[n][i])%modd;
printf("%d",an);
return 0;
}