「
「
「动态规划
」
」
」第
5
5
5章 状压
D
P
(
DP(
DP(后
2
2
2题
)
)
)
目录:
C.涂抹果酱
D.炮兵阵地
C . C. C. 例题 3 3 3 涂抹果酱
L
i
b
r
e
Libre
Libre
O
J
OJ
OJ
l
i
n
k
link
link
分析:
注意要状压成
3
3
3进制 因为有
3
3
3种颜色
f
i
,
j
f_{i,j}
fi,j表示第
i
i
i行状态为
j
j
j的方案总数
已经涂好了第
k
k
k行 那就分别从
k
−
1
k-1
k−1到
0
0
0 和
k
+
1
k+1
k+1到
n
n
n
d
p
dp
dp
两个方案数相乘 就是答案了 特判涂第
1
1
1行 和第
n
n
n行的情况
CODE:
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int Mod=1e6;
const int N=1e4+5;
int n,m,k,tot,qwq,st[55],p;
ll f[N][55],ans1,ans2;
int ksm(int a,int b)
{
int res=1;
while(b)
{
if(b&1) res=res*a;
b>>=1;
a=a*a;
}
return res;
}
bool check(int x)
{
int tmp=0x3f;
for(int i=1;i<=m;i++)
{
if(tmp==x%3) return 0;
tmp=x%3;x/=3; //3进制状压
}
return 1;
}
bool judge(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()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=m;i++)
{
int x;
scanf("%d",&x);
qwq=qwq*3+x-1;
}
int limit=ksm(3,m);
for(int i=0;i<limit;i++)
if(check(i)) st[++tot]=i;
for(int i=1;i<=tot;i++)
if(st[i]==qwq)
{
p=i;
break;
}
if(!p){
puts("0");
return 0;
}
f[k][p]=1;
for(int i=k-1;i>=1;i--)
for(int j=1;j<=tot;j++)
for(int l=1;l<=tot;l++)
if(judge(st[j],st[l]))
f[i][j]=(f[i][j]+f[i+1][l])%Mod;
for(int i=k+1;i<=n;i++)
for(int j=1;j<=tot;j++)
for(int l=1;l<=tot;l++)
if(judge(st[j],st[l]))
f[i][j]=(f[i][j]+f[i-1][l])%Mod;
for(int i=1;i<=tot;i++)
ans1=(ans1+f[1][i])%Mod;
for(int i=1;i<=tot;i++)
ans2=(ans2+f[n][i])%Mod;
if(k==1)
printf("%lld",ans2%Mod);
else if(k==n)
printf("%lld",ans1%Mod);
else printf("%lld",(ans1*ans2)%Mod);
return 0;
}
D . D. D. 例题 4 4 4 炮兵阵地
分析:
状压
d
p
dp
dp
之前写过
b
l
o
g
blog
blog 不多赘述
改了码风
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=105;
int n,m,f[N][66][66],ovo[N],val[N<<1],qwq[N],tot=0;
bool v[N][N];
char x;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>x;
if(x=='H') v[i][j]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
ovo[i]=(ovo[i]<<1)+v[i][j];
qwq[++tot]=0;
for(int i=1;i<(1<<m);i++)
{
if((i&(i<<1))||(i&(i<<2))||(i&(i>>1))||(i&(i>>2))) continue;
qwq[++tot]=i;
int p=i;
while(p)
{
val[tot]++;
p-=(p&(-p));
}
}
for(int i=1;i<=tot;i++)
if((qwq[i]&ovo[1])==0)
f[1][i][0]=val[i];
for(int i=1;i<=tot;i++)
if((qwq[i]&ovo[2])==0)
for(int j=1;j<=tot;j++)
if((qwq[i]&qwq[j])==0&&(qwq[j]&ovo[1])==0)
f[2][i][j]=val[i]+val[j];
for(int i=3;i<=n;i++)
for(int j=1;j<=tot;j++)
if((qwq[j]&ovo[i])==0)
for(int k=1;k<=tot;k++)
if((qwq[j]&qwq[k])==0&&(qwq[k]&ovo[i-1])==0)
for(int l=1;l<=tot;l++)
if((qwq[j]&qwq[l])==0&&(qwq[k]&qwq[l])==0&&(qwq[l]&ovo[i-2])==0)
f[i][j][k]=max(f[i][j][k],f[i-1][k][l]+val[j]);
int ans=0;
for(int i=1;i<=tot;i++)
for(int j=1;j<=tot;j++)
ans=max(ans,f[n][i][j]);
printf("%d",ans);
return 0;
}