zoukankan      html  css  js  c++  java
  • 51nod 1557 两个集合 (严谨的逻辑题)

    题目:

    题目来源: CodeForces
    基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题

    小X有n个互不相同的整数: p1,p2,...,pn 。他想把这些整数分到两个集合A和B里边。但是要符合下面两个条件。

    ·        如果x属于A,那么a-x也肯定属于A。

    ·        如果x属于B,那么b-x也肯定属于B。

    判断一下是否存在一种方案来分配这些数字到集合A,B中。

    注意:如果一个集合为空也是可以的。

    Input
    单组测试数据。
    第一行有三个整数n,a,b (1≤n≤10^5; 1≤a,b≤10^9)。
    第二行有n个不一样的整数 p1,p2,...,pn (1≤pi≤10^9).
    Output
    如果可行,那么输出YES,否则输出NO。
    Input示例
    样例输入1
    4 5 9
    2 3 4 5
    Output示例
    样例输出1
    YES





















    题意很清楚就是把所有的数字按要求分在A,B集合中,看是否能全部分完。


    看似很简单,但是有很多坑点,需要把所有的逻辑都想清楚再下笔。

    解法:
        首先我们看到这道题肯定会想到二分图的解法。
        二分图是相邻的点要染成不同色,看是否能把整个图只用两种颜色染色。
        这道题是相邻的点(a[i]+a[j]==A || a[i]+a[j]==B)要染成同色,看是否能用两种颜色表示。(注意的是两种颜色可能相同(A == B))
        但是和二分图很不同的是,当一个点可以在A中而且可以在B中时,用二分图的逻辑有点行不通了。

      所以我们换个思路:
        
        当某个点只能存在A中/只能存在于B中时,我们就把这个点和与之匹配的点(A-a[i]/B-a[i])放在A/B中。
        一趟一趟的扫所有的点,如果某一次没有能放在A/B中的点了,
          1.n个点中还有点没有被放在A/B中,那就不能分完,输出NO。
          2.n个点全部放在A/B中了,那就能分完,输出YES。

        注意的就是如果A == B,可能会陷入死循环,需要特殊处理A == B,直接看是否能将全部点放在A/B中就可以。


    代码:
    #include <iostream>
    #include <algorithm>
    #include <map>
    #include <vector>
    #include <set>
    #include <math.h>
    #include <queue> 
    using namespace std;
    typedef long long ll;
    #define INF 2147483647
    
    int s[100010];
    
    
    map<int, bool> in; // 表示数字没有被使用过,所有的数字都在大集合里 
    
    int main(){
        int n,a,b;
        cin >> n >> a >> b;
        for(int i = 0;i < n; i++){
            cin >> s[i];
            in[s[i]] = true;
        }
        
        int count = 0;    //记录多少个数字被使用过 
        
        while(true){
            //标记当前循环是否有数字匹配 
            bool update = false;
            
            for(int i = 0;i < n; i++){ 
                if(!in[s[i]]) continue;    //这个数字被使用过了,不再计算 
                if(in[a-s[i]] && !in[b-s[i]]){
                    //在A集合中能找到匹配对象,B集合中找不到,一定要放在A集合中 
                    in[a-s[i]] = false;    
                    in[s[i]] = false;
                    count += 2;
                    update = true;
                }else if(!in[a-s[i]] && in[b-s[i]]){
                    //在B集合中能找到匹配对象,A集合中找不到,一定要放在B集合中
                    in[b-s[i]] = false;
                    in[s[i]] = false;
                    count += 2;
                    update = true;
                }else if(in[a-s[i]] && in[b-s[i]] && a == b){
                    //如果a == b,全部放在一个集合中就可以了 
                    in[a-s[i]] = false;    
                    in[s[i]] = false;
                    count += 2;
                    update = true;
                }
            }
            //如果放了n个数字了,说明可以分配 
            if(count >= n) break;
            //如果放不够n个数字,而且再也找不到匹配了,说明无法分配 
            if(!update){
                cout << "NO" << endl;
                return 0;
            }
        }
        cout << "YES" << endl;
        return 0;
    } 



  • 相关阅读:
    企业架构-发布【企业架构框架-TOGAF v0.1.pdf】
    dropbox连接不上解决方法
    信息系统开发平台OpenExpressApp - 框架待完善工作事项
    微软全球Web Camps大会5月着落中国,免费报名参加2天原汁原味的活动,赶快报名
    BABOK - 企业分析(Enterprise Analysis)概要
    DNN(DotNetNuke)研究手札系列3-框架(概述)
    DNN(DotNetNuke)研究手札系列5之DNN的未来(蓝图)
    我乐意为博客园贡献一份力量:请签名
    DNN(DotNetNuke)研究手札系列4-框架(硬伤) 1
    感慨 20 之开源的前途/钱图?(1数据库)
  • 原文地址:https://www.cnblogs.com/zhangjiuding/p/7766469.html
Copyright © 2011-2022 走看看