图论专题班——二分图例题与练习

图论专题班——二分图例题与练习

染色判定二分图

Graph Coloring I
题意:
判定无向连通图是不是二分图
如果是输出染色方案,否则输出奇环长和环上点的编号
思路:
显然如果是二分图输出染色方案即可,不是二分图一定存在奇环,不会存在 − 1 -1 1 的情况
存在偶环二分图也是一样能染色成功的,必须是奇环才会有冲突
染色问题很好解决, d f s dfs dfs b f s bfs bfs 都可以很简单的实现
但是找奇环这个有点麻烦
在有向图中,tarjan算法 可以用来求强连通分量
这里求奇环也可以类似的实现

(其实这个题目就是个找奇环的,染色谁不会啊
code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define mem(x, d) memset(x, d, sizeof(x))
#define eps 1e-6
using namespace std;
const int maxn = 1e6 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
vector <int> e[maxn], ans;
int st[maxn], top, color[maxn];
bool ok = 1;

void dfs(int x){
	if(!ok) return;
	st[++top] = x;
	for(int to : e[x]){
		if(!color[to]){
			color[to] = color[x] == 1 ? 2 : 1;
			dfs(to);
		}
		else if(ok && color[to] == color[x]){
			ok = 0; int t;
			do{
				t = st[top--];ans.push_back(t);
			}while(t != to);// 这里的找奇环是截至到to
			return;
		}
	}
	top--;// 细节,tarjan 算法中不会有pop掉这个操作
}
void work()
{
	cin >> n >> m;
	for(int i = 1; i <= m; ++i){
		int x, y;cin >> x >> y;e[x].push_back(y);e[y].push_back(x);
	}
	color[1] = 1;
	dfs(1);
	if(ok){
		cout << 0 << endl;for(int i = 1; i <= n; ++i) cout << color[i] - 1 << " ";
	}
	else {
		cout << ans.size() << endl;for(auto x : ans) cout << x << " ";cout << endl;
	}
}

int main()
{
	ios::sync_with_stdio(0);
//	int TT;cin>>TT;while(TT--)
	work();
	return 0;
}

图的遍历
题意:
无向图有 n n n 个点,从点 1 1 1 开始遍历,但是规定:按照每次“走两步”的方式来遍历整个图。可以发现按照每次走两步的方法,不一定能够遍历整个图,问最少加几条边,可以完整的遍历整个图。
思路:
虽然题目没说,但是这个图可能不连通
那么首先要保证图联通,那么需要 连 通 块 数 − 1 连通块数-1 1 条边
可以发现,如果存在奇环,那么它就可以遍历所有的点
如果不存在,就加一条边形成奇环
code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define eps 1e-6
using namespace std;
const int maxn = 3e5 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
vector <int> e[maxn];
int color[maxn];
int ans = 0, ok = 1;
void dfs(int x)
{
	for(int i = 0; i < e[x].size(); ++i){
		int to = e[x][i];
		if(!color[to]){
			color[to] = color[x] == 1 ? 2 : 1;
			dfs(to);
		}
		else if(color[to] == color[x]) ok = 0;
		// 注意这里不能 return,要继续染色
	}	
}
void work()
{
	cin >> n >> m;
	for(int i = 1, x, y; i <= m; ++i){
		cin >> x >> y;e[x].push_back(y); e[y].push_back(x);
	}
	for(int i = 1; i <= n; ++i) if(!color[i])
	{
		++ans;
		color[i] = 1;
		dfs(i);
	}
	cout << ans - 1 + ok << endl;
}

int main()
{
	ios::sync_with_stdio(0);
//	int TT;cin>>TT;while(TT--)
	work();
	return 0;
}

小白月赛43–全体集合
题意:
给出 n n n 个点 m m m 条边 的无向图,给出 k k k 个点,这 k k k 个点上每个点都有一个人,每个人每回合能走到一个相邻的节点(不能停留不走),问:有没有可能在某一个回合,让这些人都集中在一个点?
思路:
如果图是二分图,需要所有人在同一个颜色的点上
如果不是二分图,那么就一定存在奇环,就一定可以
code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define eps 1e-6
using namespace std;
const int maxn = 2e5 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m, k;

vector <int> e[maxn];
int color[maxn];
bool ok = 0;
void dfs(int x)
{
	for(int to : e[x]) if(!color[to])
	{
		color[to] = color[x] == 1 ? 2 : 1;
		dfs(to);
	}
	else if(color[to] == color[x]){
		ok = 1;return;
	}
}

void work()
{
	cin >> n >> m >> k;
	for(int i = 1, x, y; i <= m; ++i){
		cin >> x >> y;
		e[x].push_back(y);e[y].push_back(x);
	}
	color[1] = 1;
	dfs(1);
	set<int> se;
	for(int i = 1, x; i <= k; ++i){
		cin >> x;
		se.insert(color[x]);
	}
	if(ok || se.size() == 1) cout << "YES";
	else cout << "NO";
}

int main()
{
	ios::sync_with_stdio(0);
//	int TT;cin>>TT;while(TT--)
	work();
	return 0;
}

二分图最大匹配

棋盘覆盖
题意:
思路:
code:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值