问题:
动物园里有 $n $头麋鹿。每头麋鹿有两支茸角,每支茸角有一个重量。
然而,一旦某头麋鹿上两支茸角的重量之差过大,这头麋鹿就会失去平衡摔倒。为了不然这种悲剧发生,动物园院长决定交换某些茸角,使得任意一头麋鹿的两角重量差不超过$ c$。
然而,交换两支茸角十分麻烦,不仅因为茸角需要多个人来搬运,而且会给麋鹿造成痛苦。因此,你需要计算出最少交换次数,使得任意一头麋鹿的两角重量差不超过 \(c\)。
注意,交换两支茸角只能在两头麋鹿之间进行。因为交换同一头麋鹿的两支角是没有意义的。
解:
这道题思路真的不容易想到
首先我想了半天 发现普通的状态无法推导
然后我看了一眼题解 还是 感觉 思路真的难想到
首先 我们应该先抛开 最小交换的条件 而去考虑不满足条件的因素
我们贪心一下
显然就是 排完序后 两两 之差 \(>c\)
满足条件的情况 就是 两两之差 \(<=c\)
然后我们考虑 状态压缩 首先我们先设 f[i]为 集合i 里面都满足条件的最小步数
\(f[i]=min(f[j]+\)\(f[i\)^\(j])\);
考虑区间合并
这道题另一个思路清奇的地方
为什么这么做是对的,所以 我们可以对于那些需要全部交换的,答案就是sum-1
而对那些有的不需要交换的 可以通过子集递推
code:
//
#include<bits/stdc++.h>
using namespace std;
#define maxnn 1000000
int n;
int a1[maxnn],a2[maxnn];
int tmp[maxnn];
int tot=0;
int f[maxnn];
int all=0;
#define inf 10000000
int c;
int main()
{
cin>>n>>c;
all=(1<<n)-1;
for(int i=1;i<=n;i++)
{
scanf("%d",&a1[i]);
scanf("%d",&a2[i]);
}
for(int s=0;s<=all;s++)
{
tot=0;
int ty=0;
int fla1=1;
for(int i=1;i<=n;i++)
{
if(s&(1<<i-1))
{
ty++;
tmp[++tot]=a1[i];
tmp[++tot]=a2[i];
if(abs(a1[i]-a2[i])>c) fla1=0;
}
}
sort(tmp+1,tmp+1+tot);
int fla=1;
for(int i=tot;i>=2;i-=2)
{
if(tmp[i]-tmp[i-1]>c)
{
fla=0;
}
}
if(fla==0) f[s]=inf;
else
if(fla1==1) f[s]=0;
else
f[s]=ty-1;
}
for(int s=0;s<=all;s++)
{
for(int i=s;i;i=(i-1)&s)
{
int k=s^i;
f[s]=min(f[s],f[i]+f[k]);
}
}
if(f[all]!=inf) cout<<f[all];
else cout<<-1;
}
原文:https://www.cnblogs.com/OIEREDSION/p/11454743.html