ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Codeforces Round #692 (Div. 2) C. Peaceful Rooks(图论,并查集)

2021-02-21 23:32:16  阅读:305  来源: 互联网

标签:692 Rooks int 查集 number 对角线 test cases include


题目描述

You are given a n×n chessboard. Rows and columns of the board are numbered from 1 to n. Cell (x,y) lies on the intersection of column number x and row number y.
Rook is a chess piece, that can in one turn move any number of cells vertically or horizontally. There are m rooks (m<n) placed on the chessboard in such a way that no pair of rooks attack each other. I.e. there are no pair of rooks that share a row or a column.
In one turn you can move one of the rooks any number of cells vertically or horizontally. Additionally, it shouldn’t be attacked by any other rook after movement. What is the minimum number of moves required to place all the rooks on the main diagonal?
The main diagonal of the chessboard is all the cells (i,i), where 1≤i≤n.

Input

The first line contains the number of test cases t (1≤t≤103). Description of the t test cases follows.
The first line of each test case contains two integers n and m — size of the chessboard and the number of rooks (2≤n≤105, 1≤m<n). Each of the next m lines contains two integers xi and yi — positions of rooks, i-th rook is placed in the cell (xi,yi) (1≤xi,yi≤n). It’s guaranteed that no two rooks attack each other in the initial placement.
The sum of n over all test cases does not exceed 105.

Output

For each of t test cases print a single integer — the minimum number of moves required to place all the rooks on the main diagonal.
It can be proved that this is always possible.

Example

input
4
3 1
2 3
3 2
2 1
1 2
5 3
2 3
3 1
1 2
5 4
4 5
5 1
2 2
3 3
output
1
3
4
2

Note

Possible moves for the first three test cases:
(2,3)→(2,2)
(2,1)→(2,3), (1,2)→(1,1), (2,3)→(2,2)
(2,3)→(2,4), (2,4)→(4,4), (3,1)→(3,3), (1,2)→(1,1)

题目大意

有一个n*n的棋盘,其中有m个车(象棋里的车)。求在这些车不会相互攻击到的情况下,将它们全部移到右对角线(即所有横坐标等于纵坐标的点)上需要的最小步数。

题目分析

在这个题中,最好的情况就是一步就能移动到对角线上。但是有些时候某些点并不能一次就移到对角线上,如(1,2)和(2,1)。

我们可以将所有点 ( x , y ) (x,y) (x,y) 拆成一条 x − y x-y x−y 的无向边。如果某些点变成的边连成了一个环,那么这个环上就必须有一个点要移动两次才能到达对角线上
因为此时的点(x,y)不论是移动到(x,x)还是(y,y)上都会被其它的车攻击到。因此需要有某个点先走一步离开环(先将环破坏),再移动到对角线上

这样我们就只需要找出所有点对构成的图中有多少环即可。最后的答案即为:不在对角线上的点数(如果某点一开始就在对角线上,那么连一步移动也省了)+图的环数。

找环我们可以用并查集来实现。每读入一个点(x,y),我们就用并查集合并x和y。但是如果x和y已经在一个集合中了,那就说明加入该点(x,y)之后构成了一个环。

代码如下
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
#include <unordered_map>
#include <queue>
#include <vector>
#include <set>
#include <bitset>
#include <algorithm>
#define LL long long
#define PII pair<int,int>
#define x first
#define y second
using namespace std;
const int N=2e5+5,mod=1e9+7;
int p[N];
int find(int x)			//并查集模板
{
	if(p[x]!=x) p[x]=find(p[x]);
	return p[x];
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n,m;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++) p[i]=i;		//初始化
		int ans=0;
		for(int i=1;i<=m;i++)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			if(x==y) continue;				//如果x和y一开始就在对角线上,那么一步移动也不用了
			x=find(x),y=find(y);
			if(x==y) ans++;				//如果x和y在一个集合中,说明构成了环,答案+1
			else p[x]=y;				//否则将它们合并到一个集合中
			ans++;						//加上一步移动
		}
		printf("%d\n",ans);
	}
    return 0;
}

标签:692,Rooks,int,查集,number,对角线,test,cases,include
来源: https://blog.csdn.net/li_wen_zhuo/article/details/113924175

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有