二分图
https://vjudge.net/contest/286149#problem/G 专题连接
1.判二分图
The Accomodation of Students
//bfs法
//先把一个点染色,然后把他周围联通的所有节点染色,如果染得颜色冲突,则不能形成二分图,如果没有染色,则染一个相反的颜色。 #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #include<queue> using namespace std; const int maxm = 205; int line[maxm][maxm], used[maxm], nxt[maxm]; int col[maxm]; int n, m, u, v; bool fid(int x) { for(int i = 1; i <= n; i++) { if(line[x][i] && !used[i]) { used[i] = 1; if(nxt[i] == 0 || fid(nxt[i])) { nxt[i] = x; return true; } } } return false; } int match() { int sum = 0; for(int i = 1; i <= n; i++) { memset(used, 0, sizeof(used)); if(fid(i)) sum++; } return sum; } bool bfs() { for(int i = 1; i <= n; i++) { if(col[i] == -1) { col[i] = 0; queue<int> q; q.push(i); while(!q.empty()) { int k = q.front(); q.pop(); for(int j = 1; j <= n; j++) { if(line[k][j] && col[j] == col[k]) { return 0; } if(line[k][j] && col[j] == -1) { col[j] = 1 - col[k]; q.push(j); } } } } } return 1; } int main() { while(~scanf("%d%d", &n, &m)) { memset(col, -1, sizeof(col)); memset(line, 0, sizeof(line)); memset(nxt, 0, sizeof(nxt)); while(m--) { scanf("%d%d", &u, &v); line[u][v] = line[v][u] = 1; } if(!bfs()) { printf("No\n"); continue; } printf("%d\n", match() / 2); } return 0; }
#include<vector> using namespace std; static const int MAX = 10000; vector<int> G[MAX]; //图 int V; //顶点数量 int color[MAX]; //每个点的颜色(1,-1) //将顶点v染成颜色c,成功染色返回true,否则返回false bool dfs(int v, int c) { color[v] = c; for (int i = 0; i < G[v].size(); i++) { if (color[G[v][i]] == c) return false; //相邻的点的颜色相同 if (color[G[v][i]] == 0 && !dfs(G[v][i], -c)) return false; } //所有点都染好颜色了 return true; } void solve() { for (int i = 0; i < V; i++) if (color[i] == 0) if (!dfs(i, 1)) //未染色 { printf("No\n"); return; } printf("Yes\n"); }
https://blog.csdn.net/flynn_curry/article/details/52966283
这个讲了最大匹配,最小点覆盖,最小边覆盖,最大独立自己等等。
Courses
二分图邻接举证模板,复杂度势N* M;
题意:n个课,m个人,保证取出所有课,所有课对应一个人。
输入能上这个课的人的编号;例如 3 1 2 3 如果是在第一行,表示能上第一堂课的人有3个,分别是1,2,3.
显示建二分图,左边表示课程,右边表示学生,如果学生能上某个可就连一条边,然后求最大匹配。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxm = 305; int line[maxm][maxm], used[maxm], nxt[maxm]; int t, p, n, m, u, v; bool fid(int x) { for(int i = 1; i <= n; i++) { if(line[x][i] && !used[i]) { used[i] = 1; if(nxt[i] == 0 || fid(nxt[i])) { nxt[i] = x; return true; } } } return false; } int match() { int sum = 0; for(int i = 1; i <= p; i++) { memset(used, 0, sizeof(used)); if(fid(i)) sum++; } return sum; } int main() { scanf("%d", &t); while(t--) { scanf("%d%d", &p, &n); memset(line, 0, sizeof(line)); memset(nxt, 0, sizeof(nxt)); for(int i = 1; i <= p; i++) { scanf("%d", &m); while(m--) { scanf("%d", &v); line[i][v] = 1; } } if(p > n) { printf("NO\n"); continue; } if(match() == p) { printf("YES\n"); } else { printf("NO\n"); } } return 0; }
//邻接表版本。
#include<cstdio> #include<algorithm> #include<cstring> #include<vector> using namespace std; const int maxm = 605; vector<int> ve[maxm]; int match[maxm]; bool used[maxm]; int t, p, n, m; void add(int u, int v) { ve[u].push_back(v); ve[v].push_back(u); } bool dfs(int v) { used[v] = 1; for(int i = 0; i < ve[v].size(); i++) { int u = ve[v][i]; int w = match[u]; if(w < 0 || (!used[w] && dfs(w) )) { match[v] = u;; match[u] = v; return true; } } return false; } int ma() { int res = 0; memset(match, -1, sizeof(match)); for(int i = 1; i <= p; i++) { if(match[i] < 0) { memset(used, 0, sizeof(used)); if(dfs(i)) { res++; } } } return res; } int main() { scanf("%d", &t); while(t--) { scanf("%d%d", &p, &n); for(int i = 1; i <= p + n; i++) { ve[i].clear(); } int v; for(int i = 1; i <= p; i++) { scanf("%d", &m); while(m--) { scanf("%d", &v); add(i, v + p); } }
//建图过程中把课程编号为1-p,把学生编号为p + 1, p + n;然后进行二分图匹配。 if(p > n) { printf("NO\n"); continue; } if(ma() == p) { printf("YES\n"); } else { printf("NO\n"); } } return 0; }
https://wenku.baidu.com/view/63c1a01655270722192ef7c3.html
https://blog.csdn.net/juncoder/article/details/38346193
建图方式的博客。主要是建图。