前言
题意 :
给定一个
2
∗
n
2*n
2∗n的只包括
∗
.
*.
∗.的矩阵,询问将所有
∗
*
∗合并为一个的最小代价
思路 :
赛时没思路,赛后发现是
d
p
dp
dp
状态表示 :
f
[
i
]
[
0
/
1
]
f[i][0/1]
f[i][0/1] 表示 当前这一列向上 和 向下合并
状态计算 :
-
g
[
i
]
[
0
]
=
=
∗
g[i][0]= = *
g[i][0]==∗
f [ i ] [ 1 ] = m i n ( f [ i − 1 ] [ 0 ] , f [ i − 1 ] [ 1 ] ) + 2 f[i][1]=min(f[i-1][0],f[i-1][1])+2 f[i][1]=min(f[i−1][0],f[i−1][1])+2
因为第一格子也有 ∗ * ∗,因此不仅需要从左边向右移动一位同时还需要将上面的往下合并因此需要 2 2 2代价 -
g
[
i
]
[
0
]
≠
∗
g[i][0]\neq*
g[i][0]=∗
f [ i ] [ 1 ] = m i n ( f [ i − 1 ] [ 0 ] + 1 , f [ i − 1 ] [ 1 ] ) + 1 f[i][1]=min(f[i-1][0]+1,f[i-1][1])+1 f[i][1]=min(f[i−1][0]+1,f[i−1][1])+1
显然的前面的向上合并需要先向下移动然后同时再向右移动
另外的计算方式同理
code :
char s1[N],s2[N];
int f[N][2];
void solve(){
int n,L,R;
cin>>n>>s1+1>>s2+1;
for(int i=1;i<=n;i++) if(s1[i] == '*' || s2[i] == '*') R = i ;
for(int i=n;i;i--) if(s1[i] == '*' || s2[i] == '*') L = i ;
//如果都有那么 向上和向下合并都需要一个代价
if(s1[L] == '*' && s2[L] == '*') f[L][0] = f[L][1] = 1;
else if(s1[L] == '*') f[L][0] = 0 ,f[L][1] = 1;// 如果只是第一个有 那么向下合需要一个代价
else f[L][0] = 1, f[L][1] = 0 ;//否则因为L这个位置必然有一个*因此向上合并需要一个代价
for(int i = L+1;i<=R;i++){
//向下合并 需要在加上当前的*
if(s1[i] == '*')
f[i][1] = min(f[i-1][0],f[i-1][1])+2;
else f[i][1] = min(f[i-1][0]+1,f[i-1][1])+1;
if(s2[i] == '*')f[i][0] = min(f[i-1][0],f[i-1][1])+2;
else f[i][0] = min(f[i-1][1]+1,f[i-1][0])+1;
}
cout<<min(f[R][0],f[R][1])<<endl;
}
另一种思路 :
f
[
i
]
[
0
/
1
/
2
]
f[i][0/1/2]
f[i][0/1/2]表示当前第
i
i
i列没有格子,只有第一格有格子,只有第二格有格子
这里补充一下大佬这里略的地方,卡了挺久
为什么
f
[
i
]
[
2
]
=
m
i
n
(
f
[
i
−
1
]
[
2
]
+
2
)
f[i][2]=min(f[i-1][2]+2)
f[i][2]=min(f[i−1][2]+2)
因为在这个条件中
g
[
1
]
[
i
]
=
′
∗
′
g[1][i]='*'
g[1][i]=′∗′我们不仅需要把前面的移动到
f
[
i
]
[
2
]
f[i][2]
f[i][2]同理还需要把当前列的
∗
*
∗移动下来
code :
int f[N][3];
//枚举到第 i 列 0没有 1表示第一个格子有 2表示第二个格子有
char s1[N],s2[N];
void solve(){
int n,L,R;
cin>>n>>s1+1>>s2+1;
for(int i=1;i<=n;i++){
if(s1[i] == '*' || s2[i] == '*') R = i;
}
for(int i = 0; i<= R; i ++)
for(int j=0;j<3;j++)
f[i][j] = INF;
f[0][0] = 0;
for(int i=1;i<=n;i++){
//当前这一列都没有
if(s1[i] !='*' && s2[i] !='*'){
f[i][0] = f[i-1][0];
f[i][1] = min(f[i-1][1]+1,f[i-1][2]+2);
f[i][2] = min(f[i-1][1]+2,f[i-1][2]+1);
}else if(s1[i] == '*' && s2[i] !='*'){
//第一格有* 第二格没有*
//可用从前一列的0 转移,也可也从前一列的1转移代价是1
//从前一列的2转移代价是2
f[i][1] = min({f[i-1][0],f[i-1][1]+1,f[i-1][2]+2});
//第二格没有*
//
f[i][2] = min({f[i-1][0]+1,f[i-1][1]+2,f[i-1][2]+2});
}else if(s1[i] !='*' && s2[i] == '*'){
f[i][1] = min({f[i-1][0]+1,f[i-1][1]+2,f[i-1][2]+2});
f[i][2] = min({f[i-1][0],f[i-1][1]+2,f[i-1][2]+1});
}else{
f[i][1] = min({f[i-1][0]+1,f[i-1][1]+2,f[i-1][2]+2});
f[i][2] = min({f[i-1][0]+1,f[i-1][1]+2,f[i-1][2]+2});
}
}
cout<<min(f[n][1],f[n][2])<<endl;
}