cf Two Sets (我用二分最大匹配做的)

题意:

n个数p1,p2....pn     两个数a,b

把它们分成A,B两个集合。

若x属于A,a-x一定属于A。

若x属于B,b-x一定属于B。

问是否可能将这n个数分成两个集合。若可以,输出每个数是属于A集合还是B集合(0:集合A,1:集合B)


思路:

这题我用二分图最大匹配做的。他们用并查集,额.. 一开始就没想过并查集哩,回头再看看并查集的思路吧。

若x属于A,则a-x属于A。若a-x属于A,则x属于A。集合B同理。

两两配对,若x和y可以装进一个集合,则将它们之间连条线。然后二分图最大匹配看匹配数是否等于n。

开始时用map记录p[i]这个数在数组中的位置

剩下看代码啦,易懂


代码:

#include <cstdio>
#include <iostream>
#include <string.h>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <cmath>
#include <map>
#include <stack>
using namespace std;
int const uu[4] = {1,-1,0,0};
int const vv[4] = {0,0,1,-1};
typedef long long ll;
int const maxn = 50005;
int const inf = 0x3f3f3f3f;
ll const INF = 0x7fffffffffffffffll;
double eps = 1e-10;
double pi = acos(-1.0);
#define rep(i,s,n) for(int i=(s);i<=(n);++i)
#define rep2(i,s,n) for(int i=(s);i>=(n);--i)
#define mem(v,n) memset(v,(n),sizeof(v))
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1

int n,a,b;
int p[100005];
vector<int> graph[100005];
bool bmask[100005];
int cx[100005], cy[100005];


int findPath(int u){
    int L = graph[u].size();
    rep(i,0,L-1) if(!bmask[graph[u][i]]){
        bmask[graph[u][i]] = true;
        if(cy[graph[u][i]]==-1 || findPath(cy[graph[u][i]])){
            cy[graph[u][i]] = u;
            cx[u] = graph[u][i];
            return 1;
        }
    }
    return 0;
}
int MaxMatch(){
    int ans = 0;
    rep(i,1,n) cx[i] = cy[i ] = -1;
    rep(i,1,n) if(cx[i]==-1){
        mem(bmask,false);
        ans += findPath(i);
    }
    return ans;
}

int main(){
    map<int,int> mp;

    scanf("%d%d%d",&n,&a,&b);
    rep(i,1,n){
        scanf("%d",&p[i]);
        mp[p[i]] = i;
    }
    rep(i,1,n){
        if(mp[a-p[i]])
            graph[i].push_back(mp[a-p[i]]);
        if(mp[b-p[i]])
            graph[i].push_back(mp[b-p[i]]);
    }
    int dd = MaxMatch();
    if(dd!=n) printf("NO\n");
    else{
        printf("YES\n");
        rep(i,1,n){
            if(p[i]+p[cx[i]]==a) printf("0 ");
            else printf("1 ");
        }
        printf("\n");
    }
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值