二分图的初遇Codeforces Round 884 (Div. 1 + Div. 2) E

        最近敲码的时候发现,自己以前学的一些算法都忘记了,甚至连名字都记不住。所以我又开始写文章来进行个人记录。

        Problem - E - Codeforces

题意

给定n*m的二维矩阵。要求

  • 每个格子只包含0,1,2。
  • 包含任意2*2的小矩阵,都需要包含3种类型的元素。
  • 任意相邻元素(相同行或相同列的相邻元素),不能是同一个元素。

初始之外,给定k对对角元素(正对角或反对角),要求这k对元素,每对之间两两相等。

问是否存在这样构造的二维矩阵,如果存在,输出yes,否则输出no

        这是我第一次接触二分图的算法,花了好长的时间去看官方题解的代码,仔细思考,最后顺着它的代码手跑了一遍,才对二分图稍微有一点儿了解。所谓二分图,大多数类似的是染色,将条件限制的某几个方块染色,最后来判断改图是否能够形成。尽管如此,想把这道题给转换成二分图的形式还是很困难的。

        首先,看x与y,我们发现无非是存在两种情况,(x,y)与(x+1,y+1)相等以及(x+1,y)与(x,y+1)相等,我们完全可以把这看成是两种情况,分别用0与1两个值来表示,从而构建双向图,以0与1为两点之间的边权值。这样,我们就成功把这个问题转化为了一个染色的问题。但染色也成了一个问题,我们发现,对于一个2X2的小方格而言,左上角的方块与右侧和下侧的差值是相等的,这说明,我们完全可以通过差值来染色,而不用去纠结数字,差值无非只用两个1,2,我们可以用对应的0,1来进行代替,实现对二分图的初步转化。然后用图通用的遍历方式dfs经行遍历,时间复杂度戳戳有余。

代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const ll N=998244353;
ll n,m,k;
bool f=0;

 
int main(){
	ios::sync_with_stdio(false);
	cin.tie();
	cout.tie();
	int t;
	cin>>t;
	while(t--){
		cin>>n>>m>>k;
		f=0;
		vector<vector<PII>>ve(n+m+5);
		vector<int>c(n+m+5,-1);
		for(int i=1;i<=k;i++){
			int x,y,xx,yy;
			cin>>x>>y>>xx>>yy;
			ve[min(x,xx)].push_back({min(y+n,yy+n),x+y!=xx+yy});
			ve[min(y+n,yy+n)].push_back({min(x,xx),x+y!=xx+yy});
		}
		function<void(int,int)>dfs=[&](int x,int fa)->void{
			if(c[x]!=-1){
				if(c[x]!=fa){
					f=1;
				}
				return;
			}
			c[x]=fa;
			for(auto [i,j]:ve[x])dfs(i,j^fa);
		};
		for(int i=1;i<=n+m;i++){
			if(c[i]==-1)dfs(i,0);
			if(f)break;
		}
		if(f)printf("NO\n");
		else printf("YES\n");
	}
	
	
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值