51nod搬货物

探讨了一种特殊的搬运问题,其中货物重量必须是2的幂次才能一起搬运。通过将相同重量的货物合并,研究者提出了一种算法来确定最少的搬运次数。代码实现了这一策略,通过对重量进行位运算和计数,有效地解决了问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

现在有n个货物,第i个货物的重量是 2wi2wi 。每次搬的时候要求货物重量的总和是一个2的幂。问最少要搬几次能把所有的货物搬完。

样例解释:

1,1,2作为一组。

3,3作为一组。


 收起

输入

单组测试数据。
第一行有一个整数n (1≤n≤10^6),表示有几个货物。
第二行有n个整数 w1,w2,...,wn,(0≤wi≤10^6)。

输出

输出最少的运货次数。

输入样例

样例输入1
5
1 1 2 3 3

输出样例

样例输出1
2

今天遇到这道题可以说是我碰到一个难点了,我在网上搜索得知2^(n+1)=2^n+2^n

我们可以把所有相同的数合并,这样最后剩下几个数,就是我们要的结果了,以下是我自己熬一天写的代码:

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e6 + 5;
int d[N]={-1000};
int main() {
    int a,b,c,e,f,g=0;
    scanf("%d",&a);
    for(b=1;b<=a;++b)
        scanf("%d",&d[b]);

        for(b=1;b<=a;++b)
        for(c=b+1;c<=a;++c)
    {
        if(d[b]==d[c]) {d[b]=d[b]+1;d[c]=-1000;b--;break;}
}
for(b=1;b<=a;++b)
    if(d[b]>0) g++;
printf("%d",g);
    return 0;
}
通过这个代码我们发现仅仅只有四组过了,我经过一个改造,让其更简单的实现目标;

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e6 + 5;
int d[2*N];
int main() {
    int a,b,c,e,f,g=0;
    scanf("%d",&a);
    for(b=1;b<=a;++b)
        {scanf("%d",&c);
++d[c];}
for(b=0;b<2*N;++b)
{
    g+=d[b]%2;
    d[b+1]+=d[b]/2;
}
printf("%d",g);
    return 0;
}
这一个代码可以说是非常非常非常巧妙了,首先,他将出现过货物的重量作为数组的下标,让它+1;比如说1 1 2 3 3

那么 d【1】为2,的d【2】为1,d【3】为2,d【4】为0;就是这样

for(b=0;b<2*N;++b)
{
    g+=d[b]%2;
    d[b+1]+=d[b]/2;
}重点在于这一段的处理,如果我们一位一位的算,如果d【b】%2==0,自然说明重量为2的b次方的货物有偶数个,那么就让他除2加到下一项,因为2^(n+1)=2^n+2^n,所以就转到下一项运行,如果d【b】%2!=0,说明为单,那么结果就是1,让g+1,则就是我们需要多运一趟,但是其并不影响 d[b+1]+=d[b]/2这一项运行,因为这是整数,所以d【b】/2与(d【b】-1)/2得到的是相同的结果。最终得到我们要的得数g即为我们需要跑的趟数

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值