二进制枚举-练习

目录

一、NEFU_OJ 1172,异或的应用

二、NEFU_OJ 1205,二进制枚举模板题

三、NEFU_OJ 1505

四、NEFU_OJ 1518

五、NEFU_OJ 1641

六、NEFU_OJ 1285


固定模板

for (int i = 0; i < (1 << n); i++)
    for (int j = 0; j < n; j++)
        if(i&(1<<j))

一、NEFU_OJ 1172,异或的应用

异或,英文为exclusive OR,缩写成xor

异或(xor)是一个数学运算符。它应用于逻辑运算。异或的数学符号为“⊕”,计算机符号为“xor”。其运算法则为:

a⊕b = (¬a ∧ b) ∨ (a ∧¬b)

如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0;相异为1,相同为0;

Find different

Problem:1172

Time Limit:20000ms

Memory Limit:5000K

Description

Give an odd number n, (1<=n<=10000001)

Given you an array which have n numbers : a[1], a[2] a[3] ... a[n].They are positive num.
There are n/2 numbers which appear twice and only one number appears once.
Now you should tell me the number which appears only once.

Input

There are several test cases end with EOF. 
The first line there is a integer n.
Then the 2nd line there are n integer a[1],a[2]..a[n].

Output

For each case, output the number which appears only once.

Sample Input

7
3 2 7 2 1 7 3
1
7
11
1 1 2 2 3 3 4 4 5 5 9

Sample Output

1
7
9

Hint

数据量较大,建议用scanf读入

这题用到异或的性质。比如刚开始ans=5;两个数13,13;

5的二进制是0101,13的二进制是1101;

第一次异或,ans = 5^10,相异为1.相同为0,ans =  1000;

第二次异或,ans =  ans^10, 即1000^1101,结果为0101=5;

所以当一个数,与两个相同的数字异或时,结果仍为他本身。

#include <bits/stdc++.h>
using namespace std;
int main()
{
    ios::sync_with_stdio(false);
    int n, t, ans;
    vector<int> v;
    while (cin >> n)
    {
        ans = 0;
        while (n--)
        {
            cin >> t;
            ans ^= t;
        }
        cout << ans << '\n';
        v.clear();
    }

    //system("pause");
    return 0;
}

 二、NEFU_OJ 1205,二进制枚举模板题

和为K--二进制枚举

Problem:1205

Time Limit:1000ms

Memory Limit:65535K

Description

给出长度为n的数组,求能否从中选出若干个,使他们的和为K.如果可以,输出:Yes,否则输出No

Input

第一行:输入N,K,为数组的长度和需要判断的和(2<=N<=20,1<=K<=10^9)
第二行:N个值,表示数组中元素的值(1<=a[i]<=10^6)

Output

输出Yes或No

Sample Input

5 13
2 4 6 8 10

Sample Output

No

Hint

Source

三、NEFU_OJ 1505

陈老师加油-二进制枚举

Problem:1505

Time Limit:1000ms

Memory Limit:65535K

Description

陈老师经常开车在哈尔滨的大街上行走,假设刚开始油箱里有T升汽油,每看见加油站陈老师就要把汽油的总量
翻倍(就是乘2);每看见十字路口气油就要减少1升;最后的时候陈老师的车开到一个十字路口,然
后车就没油了------就熄火了,陈老师好痛苦啊~~~!
然后他就开始回忆,一路上一共遇到5个加油站,10个十字路口,问造成这种惨烈的境遇有多少种可能?

Input

输入一个T ,(1<=T<=100);

Output

输出可能的方案数。

Sample Input

1

Sample Output

10

Hint

Source

#include <bits/stdc++.h>
using namespace std;
int main()
{
    ios::sync_with_stdio(false);
    int T, ans = 0;
    cin >> T;
    for (int i = 0; i < (1 << 15); i++)
    {
        int temp = T;
        int cnt1 = 0, cnt2 = 0;
        for (int j = 0; j < 15; j++)
        {
            if (i & (1 << j))
            {
                temp *= 2;
                cnt1++;
            }
            else
            {
                temp -= 1;
                cnt2++;
                if (cnt2 == 10)    //最后一个十字路口时,跳出循环
                    break;
            }
        }
        if (temp == 0 && cnt1 == 5 && cnt2 == 10)
        {
            ans++;
        }
    }
    cout << ans << endl;
    //system("pause");
    return 0;
}

 四、NEFU_OJ 1518

纸牌游戏-二进制-搜索

Problem:1518

Time Limit:1000ms

Memory Limit:65535K

Description

给你一些扑克,每张都对应一个点数,分别对应1-13,K 就是13;J 是11;Q是12;
现在想从这些扑克牌中取出一些牌,让这些牌的点数的和等于一个幸运数值P,问有多少种方案?

Input

输入数据第一行为n和p,分别代表n张扑克牌和幸运数(1<=n<=20,p<=260)
接下来是这n张牌的点数;  1<=点数<=13;

Output

输出能得到P 的方案数?

Sample Input

5 5
1 2 3 4 5

Sample Output

3

Hint

Source

#include <bits/stdc++.h>
using namespace std;
int main()
{
    ios::sync_with_stdio(false);
    int n, p, a[21], ans, cnt = 0;
    cin >> n >> p;
    for (int i = 0; i < n; i++)
        cin >> a[i];
    for (int i = 0; i < (1 << n); i++)
    {
        ans = 0;
        for (int j = 0; j < n; j++)
        {
            if (i & (1 << j))
            {
                ans += a[j];
            }
        }
        if (ans == p)
            cnt++;
    }
    cout << cnt << endl;
    //system("pause");
    return 0;
}

方法二:dfs

#include <iostream>
using namespace std;
int n, tp, ans = 0;
int num = 0;
int a[30];
int dfs(int ans, int k)
{
    if (k == n + 1)
    {
        if (ans == tp)
            num++;
        return 0;
    }
    dfs(ans, k + 1);        //取这张牌
    dfs(ans + a[k], k + 1);    //不取这张牌

    return 0;
}
int main()
{
    cin >> n >> tp;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    dfs(ans, 1);
    cout << num << endl;

    return 0;
}

五、NEFU_OJ 1641

权利指数

Problem:1641

Time Limit:1000ms

Memory Limit:65535K

Description

    在选举问题中,总共有n个小团体,每个小团体拥有一定数量的选票数。如果其中m个小团体的票数和超过总票数的一半,则此
组合为“获胜联盟”。n个团体可形成若干个获胜联盟。一个小团体要成为一个“关键加入者”的条件是:在其所在的获胜联盟中,
如果缺少了这个小团体的加入,则此联盟不能成为获胜联盟。一个小团体的权利指数是指:一个小团体在所有获胜联盟中成为
“关键加入者”的次数。
    请你计算每个小团体的权利指数。

Input

输入数据的第一行为一个正整数T,表示有T组测试数据。每一组测试数据的第一行为一个正整数n(0<n<=20)。
第二行有n个正整数,分别表示1到n号小团体的票数。

Output

对每组测试数据,在同一个行按顺序输出1到n号小团体的权利指数。

Sample Input

2
1
10
7
5 7 4 8 6 7 5

Sample Output

1
16 22 16 24 20 22 16

Hint

HDU
#include <bits/stdc++.h>
using namespace std;
int main()
{
    ios::sync_with_stdio(false);
    int T, n, sum;
    int group[30], flag[30] = {0};
    cin >> T;
    while (T--)
    {
        cin >> n;
        sum = 0;
        int count[30] = {0};

        for (int i = 0; i < n; i++)
        {
            cin >> group[i];
            sum += group[i];
        }
        sum /= 2;
        for (int i = 0; i < (1 << n); i++)
        {
            memset(flag,0,sizeof(flag));
            int cnt = 0;
            for (int j = 0; j < n; j++)
            {
                if (i & (1 << j))
                {
                    cnt += group[j];
                    flag[j] = 1;
                }
            }
            if (cnt > sum)
            {
                for (int j = 0; j < n; j++)
                {
                    if (flag[j] == 1 && cnt - group[j] <= sum)
                    {
                        count[j]++;
                    }
                }
            }
        }
        for (int i = 0; i < n; i++)
            cout << count[i] << (i == n - 1 ? '\n' : ' ');
    }
    //system("pause");
    return 0;
}

六、NEFU_OJ 1285

趣味解题

Problem:1285

Time Limit:1000ms

Memory Limit:65535K

Description

    ACM程序设计大赛是大学级别最高的脑力竞赛,素来被冠以"程序设计的奥林匹克"的尊称。大赛至今已有近40年的历史,
是世界范围内历史最悠久、规模最大的程序设计竞赛。比赛形式是:从各大洲区域预赛出线的参赛队伍,于指定的时间、地点参加
世界级的决赛,由1个教练、3个成员组成的小组应用一台计算机解决7到13个生活中的实际问题。
  现在假设你正在参加ACM程序设计大赛,这场比赛有 n 个题目,对于第 i 个题目你有 a_i 的概率AC掉它,如果你不会呢,那么
这时候队友的作用就体现出来啦,队友甲有 b_i 的概率AC掉它, 队友乙有 c_i 的概率AC掉它,那么现在教练想知道你们
队伍做出 x 个题目的概率。

Input

输入一个正整数T(T<=100),表示有T组数据,对于每组数据首先输入一个 n (7<=n<=13),表示有 n 个题目,接下来输入三行,
第一行输入 n 个数a_i,第二行输入 n 个数b_i,第三行输入 n 个数c_i, 其中 a_i, b_i, c_i 的意义如题,
最后输入一个 x 表示教练想要知道你们队伍做出的题目数(x>=0)。

Output

输出一行表示结果,保留4位小数

Sample Input

2
7
0.1 0.2 0.3 0.4 0.5 0.6 0.7
0.2 0.3 0.4 0.5 0.6 0.7 0.8
0.3 0.4 0.5 0.6 0.7 0.8 0.9
1
7
0.1 0.2 0.3 0.4 0.5 0.6 0.7
0.2 0.3 0.4 0.5 0.6 0.7 0.8
0.3 0.4 0.5 0.6 0.7 0.8 0.9
5

Sample Output

0.0000
0.2811

Hint

Source

ITAK
#include <bits/stdc++.h>
using namespace std;
int main()
{
    ios::sync_with_stdio(false);
    int T, n, x;
    double a[20], b[20], c[20];
    double correct[20], error[20];
    cin >> T;
    while (T--)
    {
        cin >> n;
        for (int i = 1; i <= n; i++)
            cin >> a[i];
        for (int i = 1; i <= n; i++)
            cin >> b[i];
        for (int i = 1; i <= n; i++)
            cin >> c[i];
        cin >> x;
        for (int i = 1; i <= n; i++)
        {
            error[i] = (1 - a[i]) * (1 - b[i]) * (1 - c[i]);
            correct[i] = 1 - error[i];
        }
        double ans = 0;
        for (int i = 0; i < (1 << n); i++)
        {
            int cnt = 0;
            double t1 = 1, t2 = 1;
            for (int j = 0; j < n; j++)
            {
                if (i & (1 << j))
                {
                    cnt++;
                    t1 *= correct[j + 1];
                }
                else
                    t2 *= error[j + 1];
            }
            if (cnt == x)
                ans += t1 * t2;
        }
        cout << fixed << setprecision(4) << ans << '\n';
    }
    //system("pause");
    return 0;
}

 方法二:动态规划

#include <iostream>
#include <queue>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

int main()
{
    int t, n, x;
    double a[3][14], dp[15][15], p[15];
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d", &n);
        for (int i = 0; i < 3; i++)
            for (int j = 1; j <= n; j++)
                scanf("%lf", &a[i][j]);

        for (int i = 1; i <= n; i++)
            p[i] = 1 - (1 - a[0][i]) * (1 - a[1][i]) * (1 - a[2][i]); //先算每个题答不出的概率,用1减去就是能答出的概率

        scanf("%d", &x);
        memset(dp, 0, sizeof(dp));
        dp[0][0] = 1;
        for (int i = 1; i <= n; i++)
            for (int j = 0; j <= i; j++) //dp[i][j]表示做前i道题答对j个的概率
            {
                if (j == 0)
                    dp[i][j] = dp[i - 1][j] * (1 - p[i]); //j==0时 只能在i-1答对0道的基础上第i题也答不对
                else
                    dp[i][j] = dp[i - 1][j - 1] * p[i] + dp[i - 1][j] * (1 - p[i]); //前i题答对j道 来源于两种可能相加
                                                                                    //1.前i-1道答对j个 那么乘以第i题答不对的概率
                                                                                    //2.前i-1道答对j-1个 那么乘以i题答对的概率
            }
        if (x > n) //数据有大于x>n的可能 特判 概率为0
            //printf("%.4lf\n",0);这种写法wa了可能是编译器的问题QAQ
            printf("0.0000\n");
        else
            printf("%.4lf\n", dp[n][x]);
    }
    return 0;
}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/qq_45687002/article/details/103825116

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值