zoukankan      html  css  js  c++  java
  • 竞赛准备篇---(一)抽签问题

    问题描述:

    将写有数字的 n个纸片放入口袋中,你可以从口袋中抽取 4次纸片,每次记下纸片上的数字后都将其放回口袋中。如果这 4个数字的和是 m,就是你赢,否则就是你的朋友赢。你挑战了好几回,结果一次也没赢过,于是怒而撕破口袋,取出所有纸片,检查自己是否真的有赢的可能性。请你编写一个程序,判断当纸片上所写的数字是 k 1 ,k 2 , …, k n 时,是否存在抽取 4次和为 m的方案。如果存在,输出 Yes;否则,输出 No。

    限制条件
      1 ≤ n ≤ 50
      1 ≤ m ≤ 108
      1 ≤ k i ≤108

    输入:
    n = 3    m = 10   k = {1, 3, 5}

    输出:

    YES(1 + 1 + 3 + 5 = 10)

    解题思路:
    由于问题规模小,可以直接四重循环

     1 #include<bits/stdc++.h> 
     2 #define FOR(i, a, b) for(int i = a; i < b; i++)
     3 using namespace std;
     4 int main()
     5 {
     6     int n, m, k[55];
     7     cin >> n >> m;
     8     for(int i = 0; i < n; i++)cin >> k[i];
     9     bool ans = false; //标记是否找到解 
    10     FOR(i, 0, n)FOR(j, 0, n)FOR(r, 0, n)FOR(s, 0, n)
    11     {
    12         if(k[i] + k[j] + k[r] + k[s] == m)ans = true;
    13     }
    14     if(ans)cout<<"YES"<<endl;
    15     else cout<<"NO"<<endl;
    16 }

    拓展:

    如果问题规模扩大,n属于1到1000,上述算法肯定失效。所以必须优化算法:

    最开始我们考虑的是检查是否有ki,kj,kr,ks之和等于m,算法时间复杂度为O(n4)。转移表达式,检查是否存在ks = m - ki - kj - kr;可以想到,枚举外面三层,最后判断ks是否存在即可,判断的话可以用二分查找,这样时间复杂度降低成了O(n3log(n))。但是对于1000的数据还是需要很长的时间,所以考虑是否存在kr+ks = m - ki - kj。这种情况不能直接使用二分搜索,但是,如果事先枚举出所有的kr + ks之和,并排序,就可以进行二分搜索。这样预处理+排序+二重循环搜索时间复杂度降低成了O(n2log(n))。这样n = 1000也可以轻易地过了。

     1 #include<bits/stdc++.h> 
     2 #define FOR(i, a, b) for(int i = a; i < b; i++)
     3 using namespace std;
     4 const int maxn = 1e3 + 10;
     5 int k[maxn];
     6 int kk[maxn * maxn];
     7 int tot;
     8 int n, m;
     9 bool binary_search(int x)
    10 {
    11     int l = 0, r = tot;
    12     while(l <= r)
    13     {
    14         int m = (l + r) / 2;
    15         if(kk[m] == x)return true;
    16         if(kk [m] < x)l = m + 1;
    17         else r = m - 1; 
    18     }
    19     return false;
    20 }
    21 void init()//可以直接用STL里面的set,把两层循环枚举的和放入set中,直接判断是否存在(set中的count函数) 
    22 {
    23     for(int i = 0; i < n; i++)
    24     {
    25         for(int j = i; j < n; j++)kk[tot++] = k[i] + k[j];
    26     }
    27     sort(kk, kk + tot);//排序 
    28 }
    29 int main()
    30 {
    31     cin >> n >> m;
    32     for(int i = 0; i < n; i++)cin >> k[i];
    33     init();
    34     bool ans = false; //标记是否找到解 
    35     FOR(i, 0, n)FOR(j, 0, n)
    36     {
    37         if(binary_search(m - k[i] - k[j]))ans = true; 
    38     }
    39     if(ans)cout<<"YES"<<endl;
    40     else cout<<"NO"<<endl;
    41 }
    NOIP普及组、提高组培训,有意可加微信fu19521308684
  • 相关阅读:
    “图”以致用组
    水体频率小组
    2021年云开发组三等奖作品展示
    毫秒级百万数据分页存储过程[欢迎转载]
    SQL Server 数据备份存储过程[原创]
    博客园居然被中国电信提醒有病毒,有图为证
    网络文件夹例子
    小技巧:在DropDownList数据绑定前插入固定文字
    ASP.NET整合Discuz!NT3.5实例说明(含用户登录、评论等)
    Visual Studio 2008的性能改进以及十大新功能(转)
  • 原文地址:https://www.cnblogs.com/fzl194/p/8666281.html
Copyright © 2011-2022 走看看