zoukankan      html  css  js  c++  java
  • CF1012B Solution

    题目链接

    题解

    可以发现,能够使另一个方格填色的三个方格的坐标可以写为((a,b),(a,c),(c,d)),由((a,b))(a)为检索可以找到((a,c)),而((a,c))(c)为检索找到((c,d))。由此想到,将行、列数构造为点,而每一个方格则是一条无向边。如题目样例3可构造为如下的图:

    其中深蓝色的边是题目中已给出的格子。例如((C_5,C_2,C_1,C_6))四个联通的点即可推断出一条新边(C_5C_6),图中用黄色笔画出,代表格子((1,1))可以被填充,其余黄边同理。而这时,点(C_7)仍未与其他点联通,也就是格子((4,1),(4,2),(4,3))未被填充。因此必须消耗一次填涂次数,添加一条边(C_7C_2)(C_7C_4,C_7C_6)亦可),也就是图中浅蓝色边。而通过这条边可以推断出另2条绿边,最终该图变为完全二分图,全部填充完毕。

    但是无法直接枚举点递归,因为这样时间为(O(nq))。可以发现,每一个连通图一定可以通过上述推导化为完全二分图,证明:当连通图中节点数(ge 3)时,一定可以划分为若干个由(3)个节点组成的连通子图,由其可连接新边使之称为环。而与该环连接的其他点一定可以通过推导与环中全部节点连接(过程略),因为此图为连通图,所有节点均可通过相邻节点与该子图(环)连接。所以只需使构造出的图成为连通图,即将所有连通子图连接,需建新边数(=)连通子图数(-1)

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=4e5+10;
    int fst[N],nxt[2*N],v[2*N],cnt;
    bool vis[N];//vis[i]:是否(1/0)已经过编号为i的节点
    void add(int x,int y)
    {
    	v[++cnt]=y;
    	nxt[cnt]=fst[x]; fst[x]=cnt;
    }
    void dfs(int x)
    {
    	vis[x]=1;
    	for(int i=fst[x];i;i=nxt[i])
    	{
    		int y=v[i];
    		if(!vis[y]) dfs(y);
    	}
    }
    int main()
    {
    	int n,m,q,ans=0;
    	scanf("%d%d%d",&n,&m,&q);
    	int x,y;
    	for(int i=1;i<=q;i++)
    	{
    		scanf("%d%d",&x,&y);
    		add(x,n+y); add(n+y,x);
    	}
    	for(int i=1;i<=n+m;i++)//统计联通子图个数
    		if(!vis[i]) {dfs(i); ans++;}
    	printf("%d",ans-1);
    	return 0;
    }
    
  • 相关阅读:
    (21)tar打包命令详解
    (19)ln命令:在文件之间建立链接(硬链接和软链接)
    (20)打包(归档)和压缩概念
    (18)文件和目录管理类的常用命令3
    SSH 登录警告:WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
    (17)文件和目录管理类的常用命令2
    (16)文件和目录管理类的常用命令1
    (15)Linux命令基本格式
    (14)Linux绝对路径和相对路径
    (13)Linux文件系统的优缺点
  • 原文地址:https://www.cnblogs.com/violetholmes/p/14341627.html
Copyright © 2011-2022 走看看