二分图

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

建图方式的博客。主要是建图。

posted @ 2019-03-07 16:38  downrainsun  阅读(175)  评论(0编辑  收藏  举报