【状态压缩dp(atcoder232,f】

题目链接

题意

给定两个序列a,b,执行下列两种操作要把a数组变成b数组所需要花费的最小代价是多少。

  • 操作
    1 选择a数组中一个元素加一或者减一,代价为x
    2 选择a数组中相邻两个元素交换位置,代价为y

分析

首先我们从题目的数据范围开始考虑,由于数组的长度n最大只有18,所以我们遍可以想到用状态压缩的做法来思考能不能完成。
我们可以用二进制中一的数量来表示已经移动好所需要的最好代价,所以我们定义状态表示为f[state],那现在重要的点就在于我们如何推出状态转移方程,在状态更新中我们需要将a数组中一个位置的值变成b数组中的值并且转移过去所以此时我们假设改变的是数组的第x个,那么此时的状态应该为f[ state | (1<<(x-1))
那这个时候我们就需要考虑这个过程中的代价是如何计算的,此时我们的state里包含的1就是我们已经计算的a的位置,例如state=11010就对应我们将a[1],a[2],a[4]变换成了b[1], b[2],b[3]。假设我们此时枚举到了第j位 那么我们的f[state|(1<<(j-1))=min(f[state|(1<<(j-1)),f[state]+abs(a[j]-b[cnt+1])*x+cnt0*y)这里的cnt代表的就是state中原本所带有处理好的a数组元素的数量,a[j]指现在state中没有的元素,abs(a[j]-b[cnt+1])指的是将j位置上的元素改变成b[cnt+1]上的元素,而cnt0指的是在j位置之前所包含0的数量,则代价位cnt0*y(例如state=10010指的是a[1],a[4]转换成b[1],b[2],则代价就是0的数量乘上y。
代码如下

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<cmath>
using namespace std;
#define int long long 
#define endl "\n"
const int N = 3e5+10;
int n,m,k;
int a[N],b[N];
int f[N];
int get(int state,int pos)//位置pos之前所有0的数量
{
    int res=0;
    for(int i = 1;i <= n;i ++)
    {
        if((state&(1<<(i-1)))==0&&i<pos)res++;
    }
    return res;
}
void solve()
{
  int x,y;
  cin>>n>>x>>y;
  for(int i = 1;i<= n;i ++)cin>>a[i];
  for(int i = 1;i <= n;i ++)cin>>b[i];
  memset(f,0x3f,sizeof f);//初始化,f[0]代表此时一个没有处理,代价位0
  f[0]=0;
  for(int i = 0;i < (1<<n);i ++)
  {
      int cnt = 0;
      for(int j = 0;j < n;j ++)
      {
          if(i>>j&1)cnt++;//当前已经处理好了多少位
      }
      for(int j = 0;j < n;j ++)
      {
          if(i&(1<<j))continue;
          f[i|(1<<j)]=min(f[i|(1<<j)],f[i]+abs(a[j+1]-b[cnt+1])*x+get(i,j+1)*y);
      }
  }
  cout<<f[(1<<n)-1]<<endl;
}
signed  main()
{
    ios_base::sync_with_stdio(0); cin.tie(0);cout.tie(0);
   int t=1;
   
   while(t--)
   {
       solve();
   }
    return 0;
}

感谢观看

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值