题目
CF1525D:点这里
题目大意:给定一个0、1序列,1代表位置被人占领,0代表没有人,要将原先的1全部移动到0的位置,并且原来被占领的位置不能有人,i移动到j的花费是abs(i-j),求最小的总花费
算法思路
- 定义状态,首先 f [ i ] [ j ] f[i][j] f[i][j]代表,前j个零中已经有i个i匹配的最小话费,
- 将1的位置全部放在a数组里面(递增),将0的位置全部放在b数组里面(递增)
- 状态初始值全部都为inf(无穷大), f [ 0 ] [ i ] f[0][i] f[0][i](i from 0 to size(b)),因为任意位置选取0个1,的最小花费都是i0
- 状态转移方程, f [ i ] [ j ] f[i][j] f[i][j]显然有 i < = j i<=j i<=j,(0的个数必然要大于1的个数),如果当前位置的0不选,那么就为上一个状态 f [ i ] [ j − 1 ] f[i][j-1] f[i][j−1],如果当前位置的0选,则 f [ i − 1 ] [ j − 1 ] + a b s ( a [ i ] − b [ j ] ) f[i-1][j-1]+abs(a[i]-b[j]) f[i−1][j−1]+abs(a[i]−b[j]),然后二则再取min,则得到状态转移方程 f [ i ] [ j ] = m i n ( f [ i ] [ j − 1 ] , f [ i − 1 ] [ j − 1 ] + a b s ( a [ i ] − b [ j ] ) ) f[i][j]=min(f[i][j-1],f[i-1][j-1]+abs(a[i]-b[j])) f[i][j]=min(f[i][j−1],f[i−1][j−1]+abs(a[i]−b[j]))
代码实现
#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
#define el '\n'
#define cl putchar('\n')
#define pb push_back
#define eb emplace_back
#define fir first
#define sec second
typedef long long ll;
typedef pair<int,int> pii;
typedef vector<int> vci;
typedef map<int,int> mii;
typedef mii::iterator mii_it;
const int N=1e5+10,M=1e3+10;
int T,n,m,x,y,k,t1,t2;
int a[N],b[N],f[5001][5001];
int main() {
cin.tie(0);
cout.tie(0);
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>x;
if(x==1)a[++t1]=i;
else b[++t2]=i;
}
memset(f,0x3f,sizeof(f));
for(int i=0;i<=t2;i++)f[0][i]=0;
for(int i=1;i<=t1;i++){
for(int j=i;j<=t2;j++){
f[i][j]=min(f[i][j-1],f[i-1][j-1]+abs(a[i]-b[j]));
//cout<<i<<" "<<j<<":"<<f[i][j]<<endl;
}
}
cout<<f[t1][t2];
// cin>>T;
// while(T--) {
//
// }
}