D. Armchairs
题面:
给一个长度为n的01序列,1表示已被占用,0表示空缺。可以将1移动到0的位置,代价为其下标差的绝对值。求将一开始被占用的位置空出来所需的最小花费。
思路
用数组pos1来储存1的下标,数组pos2来储存0的下标。
动态规划分析思路:
-
集合表示:dp[i][j]表示前i个1和前j个0匹配方案;
-
属性:最小值
-
集合的划分:dp[i][j]可以分为两部分:
第i个1一定与第j个0匹配,得到dp[i-1][j-1]+abs(pos1[i]-pos2[j]);
第i个1不与第j个0匹配,即前i个1与前j-1个0匹配,得到dp[i][j-1];
两者取最小值来跟新dp[i][j];
所以状态转移方程:dp[i][j]=min(dp[i][j-1],dp[i-1][j-1]+abs(pos1[i]-pos2[0])); -
初始化:根据状态定义将dp[0][i],0<=i<=pos2.size()初始为0(前0个1与任意j匹配花费都为0),其余为inf;**
AC代码
#include<bits/stdc++.h>
using namespace std;
const int inf=1e8;
int main()
{
int n;
cin>>n;
vector<int> pos1;
vector<int> pos2;
for(int i=1;i<=n;i++)
{
int t;
cin>>t;
if(t)
pos1.push_back(i);
else
pos2.push_back(i);
}
int k1=pos1.size(),k2=pos2.size();
vector<vector<int> > dp(k1+1,vector<int>(k2+1,inf));
for(int i=0;i<=k2;i++)
dp[0][i]=0;
for(int i=1;i<=k1;i++)
for(int j=1;j<=k2;j++)
dp[i][j]=min(dp[i][j-1],dp[i-1][j-1]+abs(pos1[i-1]-pos2[j-1]));
cout<<dp[k1][k2]<<endl;
return 0;
}