BAPC 2020 Preliminaries G-Group project (思维)

题意:
n个人分别编号为1-n,然后给出你m对的不喜欢关系
( u , v ) (u,v) (u,v)代表u和v为无法配对,这个dislike关系是没有传递性并且题目保证不会一定有解,也就是不会出现 ( 1 , 2 ) , ( 2 , 3 ) , ( 3 , 1 ) (1,2),(2,3),(3,1) (1,2),(2,3),(3,1)这种关系问你最多满足题目条件的情况下,能构造多少对二元组。

思路:
模拟把这n个人分为两组,假设i属于第一个组,那么和i相连的点都把他放到第二个组里,也就是保证每个组内都是可以互相配对的,假如最后两个组的人数都是偶数,很明显每个组内自由配对不会有剩余,一个奇数一个偶数,会剩一个人,但无法和其他人继续配对所以没办法,两个奇数,此时每个组内都会剩下一个,我们就要考虑剩下的这两个能配对嘛,假如一组里的每个人都和二组的每个人都dislike,很明显这种情况下,我们找不到一个横跨两个组的二元组使得二者互相不dislike,所以这种情况就是输出各组人数除2即可,否则就是n除2。

代码:

#include <bits/stdc++.h>

using namespace std;

#define pb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 1e5 + 10;
const int M = 2e5 + 10;
int group[N],deg[N],n,m;
int head[N],cnt;
struct node{
	int next,to;
}edge[M<<1];
void addedge(int u,int v) {
	edge[++cnt].to = v,edge[cnt].next = head[u],head[u] = cnt;
	edge[++cnt].to = u,edge[cnt].next = head[v],head[v] = cnt;
}
//这里的dislike关系没有传递性 所以比较好处理
void dfs(int u,int id) {//把所有的人分为两个组
	group[u] = id;
	for(int i = head[u];i;i = edge[i].next) {//与这个点相连的点一定要和当前点分在不同组
		int v = edge[i].to;
		if(group[v]) continue;
		dfs(v,3-id);
	}
}

int main() {
	scanf("%d%d",&n,&m);
	int a,b;
	for(int i = 1;i <= m;i ++) {
		scanf("%d%d",&a,&b);
		addedge(a,b);
		deg[a]++,deg[b]++;
	}
// 	dfs(1,0);
	int cnt1 = 0,cnt2 = 0;
	for(int i = 1;i <= n;i ++) {
		if(!group[i]) dfs(i,1);
		group[i] == 1 ? cnt1++ : cnt2++;
	}
	if((cnt1 & 1) && (cnt2 & 1)) {
		int fg = 0;
		for(int i = 1;i <= n;i ++) {
			if(group[i] == 1 && deg[i] < cnt2) { fg = 1; break; }
			if(group[i] == 2 && deg[i] < cnt1) { fg = 1; break; }
		}
		if(fg) printf("%d\n",n/2);
		else printf("%d\n",cnt1/2 + cnt2/2);
	}
	else printf("%d\n",n/2);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值