题意:
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 "); else{ printf("YES "); rep(i,1,n){ if(p[i]+p[cx[i]]==a) printf("0 "); else printf("1 "); } printf(" "); } }