题意:
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;
}