这是一个基础的二分图,题意比较好理解,给出n个人,其中有m对互不了解的人,先让我们判断能不能把这n对分成两部分,这就用到的二分图的判断方法了,二分图是没有由奇数条边构成环的图,这里用bfs染色法就可以判断,其次让我们求分在两部分的最大对数,这就是二分图的最大匹配问题,这里数据只有200,所以匈牙利算法求蹭广路径的办法可以解决这个问题,也相对比较容易编写。
另外一开始我链式前向星的数组开小了,G++居然返回超时,后来换了C++才RE,想到数组越界的问题,不得不说这些编译器真傲娇啊~
#include<iostream> #include<cstring> #include<queue> #include<cstdio> using namespace std; struct EDGE { int to,nxt; }edge[50000]; int head[220],n,m,tot; void add_edge(int x,int y) { edge[tot].to = y; edge[tot].nxt = head[x]; head[x] = tot++; } int clo[220]; bool bfs(int id) { queue<int>que; clo[id] = 1; while(!que.empty()) que.pop(); que.push(id); while(!que.empty()) { int now = que.front(); que.pop(); for(int i = head[now];i != -1;i = edge[i].nxt) { int go = edge[i].to; if(clo[go] == -1) { clo[go] = (clo[now] ^ 1); que.push(go); } else if(clo[go] == clo[now]) return false; } } return true; } bool is_erfen() { memset(clo,-1,sizeof(clo)); bool mark = true; for(int i = 1;i <= n;i++) { if(clo[i] != -1)continue; mark = bfs(i); if(mark == false) return false; } return mark; } int vis[220],link[220]; bool Find(int x) { for(int i = head[x];i != -1;i = edge[i].nxt) { int now = edge[i].to; if(vis[now]) continue; vis[now] = 1; if(link[now] == -1 || Find(link[now])) { link[now] = x; return true; } } return false; } int match() { memset(link,-1,sizeof(link)); int ans = 0; for(int i = 1;i <= n;i++) { memset(vis,0,sizeof(vis)); if(Find(i)) ans++; } return ans / 2; } int main() { while(~scanf("%d%d",&n,&m)) { tot = 0; memset(head,-1,sizeof(head)); for(int i = 0;i < m;i++) { int u,v; scanf("%d%d",&u,&v); add_edge(u,v); add_edge(v,u); } bool flag = is_erfen(); if(!flag) { printf("No\n"); } else printf("%d\n",match()); } return 0; }