二分图总结
二分图判定(染色法)
#include<cstdio>
#include<cstring>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;
const int MAXN = 2000 + 10;
const int MAXM = 1e6 + 10;
struct Edge { int to, next; };
Edge edges[MAXM << 1];
int head[MAXN], vis[MAXN];
int color[MAXN], n, m, num = 0;
void addEdge(int from, int to)
{
edges[num] = Edge{to, head[from]};
head[from] = num++;
}
bool dfs(int u)
{
vis[u] = 1;
for(int i = head[u]; ~i; i = edges[i].next)
{
int v = edges[i].to;
if(vis[v])
{
if(color[u] == color[v]) return false;
}
else
{
color[v] = color[u] ^ 1;
if(!dfs(v)) return false;
}
}
return true;
}
bool judge()
{
_for(i, 1, n)
if(!vis[i])
{
color[i] = 0;
if(!dfs(i)) return false;
}
return true;
}
int main()
{
int T;
scanf("%d", &T);
_for(kase, 1, T)
{
memset(head, -1, sizeof(head));
memset(vis, 0, sizeof(vis));
memset(color, 0, sizeof(color));
num = 0;
scanf("%d%d", &n, &m);
while(m--)
{
int u, v;
scanf("%d%d", &u, &v);
addEdge(u, v); addEdge(v, u);
}
printf("Scenario #%d:\n", kase);
if(!judge()) puts("Suspicious bugs found!\n");
else puts("No suspicious bugs found!\n");
}
return 0;
}
二分图最大匹配 ——匈牙利算法
最小覆盖点集 = 最大匹配
把矩阵上的点转化成边。点(x,y)即把x和y连一条边。
最后答案即是最小覆盖点集,又知最小覆盖点集 = 最大匹配
所以敲一遍模板就好了
#include<cstdio>
#include<cstring>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;
const int MAXN = 500 + 10;
const int MAXM = 1e4 + 10;
struct Edge
{
int to, next;
}e[MAXM];
int vis[MAXN], head[MAXN];
int link[MAXN], n, m, num, ans;
void AddEdge(int from, int to)
{
e[num] = Edge{to, head[from]};
head[from] = num++;
}
bool find(int u)
{
for(int i = head[u]; ~i; i = e[i].next)
{
int v = e[i].to;
if(vis[v]) continue;
vis[v] = 1;
if(!link[v] || find(link[v]))
{
link[v] = u;
return true;
}
}
return false;
}
int main()
{
memset(head, -1, sizeof(head)); num = 0;
memset(link, 0, sizeof(link));
scanf("%d%d", &n, &m);
while(m--)
{
int u, v;
scanf("%d%d", &u, &v);
AddEdge(u, v);
}
_for(i, 1, n)
{
memset(vis, 0, sizeof(vis));
if(find(i)) ans++;
}
printf("%d\n", ans);
return 0;
}
裸题。二分图的题目要注意点和边数组开的大小。
#include<cstdio>
#include<cstring>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std;
const int MAXN = 200 + 10;
const int MAXM = 4e4 + 10;
struct Edge{ int to, next; };
Edge e[MAXM];
int head[MAXN], vis[MAXN];
int link[MAXN], n, m, num;
void AddEdge(int from, int to)
{
e[num] = Edge{to, head[from]};
head[from] = num++;
}
bool find(int u)
{
for(int i = head[u]; ~i; i = e[i].next)
{
int v = e[i].to;
if(vis[v]) continue;
vis[v] = 1;
if(!link[v] || find(link[v]))
{
link[v] = u;
return true;
}
}
return false;
}
int main()
{
while(~scanf("%d%d", &n, &m))
{
memset(head, -1, sizeof(head));
memset(link, 0, sizeof(link));
num = 0;
_for(v, 1, n)
{
int t, u; scanf("%d", &t);
while(t--)
{
scanf("%d", &u);
AddEdge(u, v);
}
}
int ans = 0;
_for(i, 1, n)
{
memset(vis, 0, sizeof(vis));
if(find(i)) ans++;
}
printf("%d\n", ans);
}
return 0;
}