3900: 交换茸角

50 篇文章 0 订阅

3900: 交换茸角

Time Limit: 20 Sec   Memory Limit: 512 MB
Submit: 165   Solved: 72
[ Submit][ Status][ Discuss]

Description

动物园里有 n 头麋鹿。每头麋鹿有两支茸角,每支茸角有一个重量。然而,一旦某头麋鹿上
两支茸角的重量之差过大,这头麋鹿就会失去平衡摔倒。为了不然这种悲剧发生,动物园院长决
定交换某些茸角,使得任意一头麋鹿的两角重量差不超过 c。然而,交换两支茸角十分麻烦,不
仅因为茸角需要多个人来搬运,而且会给麋鹿造成痛苦。因此,你需要计算出最少交换次数,使
得任意一头麋鹿的两角重量差不超过 c。
注意,交换两支茸角只能在两头麋鹿之间进行。因为交换同一头麋鹿的两支角是没有意义的。

Input

第一行为整数 n,c。接下来 n 行,每行两个整数,分别表示一开始每头麋鹿的两角重量。

Output

一个数,即最少交换次数。如果无论如何也不能使每头麋鹿平衡,输出 -1。

Sample Input

3 0
3 3
2 5
2 5

Sample Output

1

HINT

对于 100% 的数据,n <= 16, c <= 1000000, 每支茸角重量不超过 1000000。



Source

[ Submit][ Status][ Discuss]

考虑一个较为简单的情形,有n只麋鹿,是否存在一个可行解
将茸角升序排好,贪心地想显然是相邻两个茸角配为一对,如果这样都不合法,那么肯定没有可行解了
可以证明,这种情形下至多n - 1次交换就能让所有麋鹿的茸角配对完成
考虑每只麋鹿一只角固定,移动另一只角,每次拿一个未配对的角交换到适当位置即可
那么剩下的只需写个状压dp即可,如果当前方案不够优,自然可以由拆分成子区间完成
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#include<cmath>
#include<stack>
#define min(a,b) ((a) < (b) ? (a) : (b))
using namespace std;
 
const int N = 16;
const int M = (1 << N);
 
int n,c,a[N],b[N],d[233],f[M];
 
int main()
{
    #ifdef DMC
        freopen("DMC.txt","r",stdin);
    #endif
     
    cin >> n >> c;
    for (int i = 0; i < n; i++) scanf("%d%d",&a[i],&b[i]);
    for (int o = 1; o < (1 << n); o++)
    {
        int tp = 0;
        for (int x = o,now = 0; x; x >>= 1,now++)
            if (x & 1) d[++tp] = a[now],d[++tp] = b[now];
        bool pass = 1; sort(d + 1,d + tp + 1);
        for (int i = 1; i < tp; i += 2)
            if (d[i + 1] - d[i] > c) pass = 0;
        f[o] = pass ? (tp / 2 - 1) : M;
        for (int op = o - 1 & o; op; op = op - 1 & o)
            f[o] = min(f[o],f[op] + f[o ^ op]);
    }
    cout << (f[(1 << n) - 1] == M ? -1 : f[(1 << n) - 1]) << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值