蓝桥杯 ALGO-1004 无聊的逗

试题 算法训练 无聊的逗

问题描述
  逗志芃在干了很多事情后终于闲下来了,然后就陷入了深深的无聊中。不过他想到了一个游戏来使他更无聊。他拿出n个木棍,然后选出其中一些粘成一根长的,然后再选一些粘成另一个长的,他想知道在两根一样长的情况下长度最长是多少。

输入格式   第一行一个数n,表示n个棍子。第二行n个数,每个数表示一根棍子的长度。

输出格式   一个数,最大的长度。 样例输入 4 1 2 3 1 样例输出 3 数据规模和约定   n<=15

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
typedef long long ll;
int n,a[N],b[N],tem,ans;
int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&b[i]);
    }   
    for(int i=0;i<1<<n;i++){
        for(int j=0;j<n;j++){
            if((i&(1<<j))){
                a[i]+=b[j];//进行枚举 i有哪个1就代表有哪根木棍
            }
        }
    }
    for(int i=0;i<(1<<n);i++){//对所有木棍的情况进行枚举
        int tem=(1<<n)-1-i;//tem为全集减去i=i的补集
        for(int j=tem;j>0;j=(j-1)&tem){//对子集进行枚举
            if(a[i]==a[j]){
                ans=max(ans,a[i]);
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}
关于状压DP枚举子集的优雅写法

设当前状态为S,子集状态为p,则有:

for(p = S; p; p = (p - 1) & S) {
  p1 = S ^ p;//p1为补集
	//TODO 
}

公式的验证

void fun(int k){
    for(int i=3;i>=0;i--){
        if((1<<i)&k)
            printf("1");
        else
            printf("0");
    }
    printf("\n");
}
for(int i=1;i<=15;i++){
        printf("%d 的所有子集\n",i);
        for(int j=i;j;j=(j-1)&i){
            fun(j);
        }
    }
1 的所有子集
0001
2 的所有子集
0010
3 的所有子集
0011
0010
0001
4 的所有子集
0100
5 的所有子集
0101
0100
0001
6 的所有子集
0110
0100
0010
7 的所有子集
0111
0110
0101
0100
0011
0010
0001
8 的所有子集
1000
9 的所有子集
1001
1000
0001
10 的所有子集
1010
1000
0010
11 的所有子集
1011
1010
1001
1000
0011
0010
0001
12 的所有子集
1100
1000
0100
13 的所有子集
1101
1100
1001
1000
0101
0100
0001
14 的所有子集
1110
1100
1010
1000
0110
0100
0010
15 的所有子集
1111
1110
1101
1100
1011
1010
1001
1000
0111
0110
0101
0100
0011
0010
0001

转载于这里

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值