【題解】Luogu P7171 [COCI2020-2021#3] Selotejp
注:題解中 \(\operatorname{lsh}\),\(\operatorname{rsh}\),\(\operatorname{or}\) 分別表示按位左移、按位右移、按位或,即 c++ 語言中的 <<,>>,|。
我也是打上輪廓線 DP 了。
設 \(f_{x,y,S}\) 表示當前在 \((x,y)\) 格子,前 \(m\) 個格子的狀態為 \(S\) 時的最小花費。
這里的狀態是指,這一格豎著覆蓋為 \(1\),橫著覆蓋或本來就不用覆蓋為 \(0\)。
這里的前 \(m\) 個格子如下圖所示,假設 \(m=4\),當前在 \((2,2)\),方格內的數表示在 \(S\) 中從低到高的下標(從 \(0\) 開始):

它就是一個逐行遍歷矩陣的順序,注意是包括 \((x,y)\) 這一格的。
為什么要這樣記錄呢,因為存在豎著覆蓋,如剛才的例子,\((2,2)\) 的下一個為 \((2,3)\),它的上面是 \((1,3)\),剛好被記錄了狀態。
于是轉移其實不難想:
- 下一位 \((nx,ny)\) 為
#- 橫著覆蓋,判斷左邊有沒有點,且這個點是不是橫著覆蓋的,即 \(f_{nx,ny,S\operatorname{rsh}1}\) 從 \(f_{x,y,S}\) 或 \(f_{x,y,S}+1\) 轉移。
- 豎著覆蓋,判斷上面的點是不是豎著覆蓋的,即 \(f_{nx,ny,(S\operatorname{rsh}1)\operatorname{or}(1\operatorname{lsh}(m-1))}\) 從 \(f_{x,y,S}\) 或 \(f_{x,y,S}+1\) 轉移。
- 下一位為
.,直接讓 \(f_{nx,ny,S\operatorname{rsh}1}\) 從 \(f_{x,y,S}\) 轉移。
復雜度 \(O(nm2^m)\)。
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define read(x){\
char ch;\
int fu=1;\
while(!isdigit(ch=getchar()))\
fu-=(ch=='-')<<1;\
x=ch&15;\
while(isdigit(ch=getchar()))\
x=(x<<1)+(x<<3)+(ch&15);\
x*=fu;\
}
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
const int maxn=(1<<10)+5;
const int inf=0x3f3f3f3f;
int n,m,f[maxn][15][maxn];
char s[maxn][15];
il void upd(int &x,int y){
x=min(x,y);
}
namespace cplx{
bool end;
il double usdmem(){return (&begin-&end)/1048576.0;}
}
int main(){
read(n)read(m);
for(int i=1;i<=n;i++){
scanf(" %s",s[i]+1);
}
memset(f,0x3f,sizeof f);
if(s[1][1]=='#'){
f[1][1][0]=f[1][1][1<<(m-1)]=1;
}
else{
f[1][1][0]=0;
}
for(int x=1;x<=n;x++){
for(int y=1;y<=m;y++){
for(int S=0,nx,ny;S<1<<m;S++){
if(f[x][y][S]>=inf){
continue;
}
nx=x+y/m;
ny=y%m+1;
if(s[nx][ny]=='#'){
if(ny>1&&(S>>(m-1)&1)==0&&s[x][y]=='#'){
upd(f[nx][ny][S>>1],f[x][y][S]);
}
else{
upd(f[nx][ny][S>>1],f[x][y][S]+1);
}
if(nx>1&&(S&1)){
upd(f[nx][ny][S>>1|1<<(m-1)],f[x][y][S]);
}
else{
upd(f[nx][ny][S>>1|1<<(m-1)],f[x][y][S]+1);
}
}
else{
upd(f[nx][ny][S>>1],f[x][y][S]);
}
}
}
}
int ans=inf;
for(int S=0;S<1<<m;S++){
ans=min(ans,f[n][m][S]);
}
printf("%d",ans);
return 0;
}
}
int main(){return asbt::main();}

浙公網安備 33010602011771號