(0,1移动匹配)CF1525D(区间dp)

题目

CF1525D:点这里

题目大意:给定一个0、1序列,1代表位置被人占领,0代表没有人,要将原先的1全部移动到0的位置,并且原来被占领的位置不能有人,i移动到j的花费是abs(i-j),求最小的总花费

算法思路

  1. 定义状态,首先 f [ i ] [ j ] f[i][j] f[i][j]代表,前j个零中已经有i个i匹配的最小话费,
  2. 将1的位置全部放在a数组里面(递增),将0的位置全部放在b数组里面(递增)
  3. 状态初始值全部都为inf(无穷大), f [ 0 ] [ i ] f[0][i] f[0][i](i from 0 to size(b)),因为任意位置选取0个1,的最小花费都是i0
  4. 状态转移方程, 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][j1],如果当前位置的0选,则 f [ i − 1 ] [ j − 1 ] + a b s ( a [ i ] − b [ j ] ) f[i-1][j-1]+abs(a[i]-b[j]) f[i1][j1]+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][j1],f[i1][j1]+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--) {
//
//	}
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值