题目链接:hdu 2444
题意:有n个童鞋,给出的m对童鞋是相互认识的,第一问问是否能分成两个部分,每部分之间童鞋是相互不认识的,但是和另一部分的童鞋是可以认识的,明显问你这些童鞋是否能构成二分图,连边的条件显然是是否认识。第二个问说相互认识的童鞋可以被分配一个房间,问你最大的房间数,那么就是要求二分图的最大匹配,下面我们用染色法判断是否二分,用匈牙利算法去求最大的匹配。
注意总结:
染色法的时候设置个全局变量去判断,一遇到有相邻两边同个颜色的就置为false。
怎么建立二分图?设置全局变量vN,然后把左边部分的结点号保存在left[]数组里,因为右边部分已经可以从左边部分的结点的得到(用vector保存好的),所以只要保存左边。什么是左边部分?你可以自定义颜色为一样的,比如颜色为1的当作左边。
代码:
#include<iostream> #include<cstring> #include<vector> #define MAXN 210 using namespace std; vector<int>G[MAXN]; int vis[MAXN]; bool used[MAXN]; int linker[MAXN]; int uN, lleft[MAXN]; bool istwo; void dfs(int u, int color) { if(color == 1) lleft[uN++] = u; vis[u] = color; for(int i = 0; i < G[u].size(); i++){ int v = G[u][i]; if(vis[v] == -1) dfs(v, color^1); else if(vis[v] == color) { istwo = false; return ; } } } bool find(int u) { for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if(!used[v]){ used[v] = true; if(linker[v] == -1 || find(linker[v])){ linker[v] = u; return true; } } } return false; } int hungary() { int res = 0; memset(linker, -1, sizeof(linker)); for(int i = 0; i < uN; i++){ int u = lleft[i]; memset(used, 0, sizeof(used)); if(find(u)) res++; } return res; } int main() { int n, m; while(~scanf("%d%d", &n, &m)){ int a, b; uN = 0; for(int i = 0; i < MAXN; i++) G[i].clear(); for(int i = 0; i < m; i++){ scanf("%d%d", &a, &b); G[a].push_back(b); G[b].push_back(a); } memset(vis, -1, sizeof(vis)); istwo = true; for(int i = 1; i < n; i++){ if(vis[i] == -1) dfs(i, 1); if(istwo == false) break; } if(istwo){ int res = hungary(); printf("%d\n", res); } else { printf("No\n"); } } return 0; }