题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2444
题目大意:
n个学生,他们中间有m对互相认识。有两个操作:
1、把所有人分成两组,每组中的人都互不认识。若该操作能完成,那么请考虑操作2,否则输出“No”;
2、将互相认识的两个人分配到一间双人房,问最多能分出多少间房。
其实操作1就是要我们做一个二分图判定,我们用一个DFS就能完成,详见《挑战程序设计竞赛》P97。在确定这是一个二分图的前提下,我们就能根据学生之间的关系写一个匈牙利算法来求最大匹配数,最大匹配数其实就是最多的房间数。由于在程序中,我把每个房间当成了两个来进行匹配,所以最后的最大匹配数要除以2。
AC代码:
1 #include <cstring> 2 #include <vector> 3 #include <cstdio> 4 using namespace std; 5 const int maxn=204; 6 bool link[maxn][maxn], vis[maxn]; 7 int r[maxn],n,color[maxn]; 8 vector<int> G[maxn]; 9 bool finds(int x){ 10 for(int i=1;i<=n;i++){ 11 if(!vis[i]&&link[x][i]){ 12 vis[i]=true; 13 if(r[i]==0||finds(r[i])){ 14 r[i]=x; 15 return true; 16 } 17 } 18 } 19 return false; 20 } 21 bool dfs(int v,int c){ 22 color[v]=c; 23 for(int i=0;i<G[v].size();i++){ 24 if(color[G[v][i]]==c) return false; 25 if(color[G[v][i]]==0&&!dfs(G[v][i],-c)) return false; 26 } 27 return true; 28 } 29 bool yes_no(){ 30 for(int i=1;i<=n;i++){ 31 if(color[i]==0){ 32 if(!dfs(i,1)) return false; 33 } 34 } 35 return true; 36 } 37 int main(){ 38 int m,a,b; 39 while(scanf("%d%d",&n,&m)==2){ 40 memset(color,0,sizeof(color)); 41 memset(link,false,sizeof(link)); 42 memset(r,0,sizeof(r)); 43 for(int i=1;i<=n;i++) G[i].clear(); 44 while(m--){ 45 scanf("%d%d",&a,&b); 46 G[a].push_back(b),G[b].push_back(a); 47 link[a][b]=link[b][a]=true; 48 } 49 if(!yes_no()){ 50 printf("No "); 51 continue; 52 } 53 int ans=0; 54 for(int i=1;i<=n;i++){ 55 memset(vis,false,sizeof(vis)); 56 if(finds(i)) ans++; 57 } 58 printf("%d ",ans/2); 59 } 60 return 0; 61 }