题意简述
就是给你一个01字串,每一次把1的位置挪到0的位置的代价是|i-j|总代价是加和,请问把所有1的位置,挪动到0的位置的代价最小值?
思路
本题可以将0的位置和1的位置分割开来分析
dp[i][j]代表将前i个1挪动到前j个0的位置的代价最小值。
那么我们就可以列出状态转移方程
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
]
[
j
−
1
]
,
d
p
[
i
−
1
]
[
j
−
1
]
+
a
b
s
(
p
1
[
i
]
−
p
0
[
j
]
)
dp[i][j]=min(dp[i][j-1],dp[i-1][j-1]+abs(p1[i]-p0[j])
dp[i][j]=min(dp[i][j−1],dp[i−1][j−1]+abs(p1[i]−p0[j])
闫式dp分析法
状态划分:两组
一组是我什么都不用干,i个1已经放在前j-1的位置上了,而且保证最小
还有一种就是需要把第i个1的字符其他位置上,这样枚举一下位置就可以。
代码
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int dp[5002][5002];
int p1[5002];
int p0[5002];
int main(){
int n;
cin>>n;
int a=0,b=0;
for(int i=1;i<=n;i++){
int u;
cin>>u;
if(u)p1[++a]=i;
else p0[++b]=i;
}
memset(dp,0x3f,sizeof dp);
for(int i=0;i<=n;i++)dp[0][i]=0;
for(int i=1;i<=a;i++)
for(int j=1;j<=b;j++){
dp[i][j]=min(dp[i][j-1],dp[i-1][j-1]+abs(p1[i]-p0[j]));
}
cout<<dp[a][b]<<endl;
}