和谐并处的车【牛客tracker & 每日一题】
和谐并处的车
时间限制:1秒 空间限制:256M
网页链接
牛客tracker
牛客tracker & 每日一题,完成每日打卡,即可获得牛币。获得相应数量的牛币,能在【牛币兑换中心】,换取相应奖品!助力每日有题做,丰盈牛币日益多!
题目描述
给定一个 n × n n×n n×n 的象棋棋盘。棋盘的行和列编号从 1 1 1 到 n n n 。单元格 ( x , y ) (x,y) (x,y) 位于第 x x x 列和第 y y y 行的交点。
“车” 是一种国际象棋棋子,每一步可以沿着垂直或水平方向移动任意格数。棋盘上有 m m m 个车( m < n m<n m<n ),它们被放置在棋盘上,且任意两个车不会互相攻击。也就是说,没有任意一对车处于同一行或同一列。
每一步,你可以选择一个车,将其沿垂直或水平方向移动任意格数。移动后,该车不能被其他任何车攻击。请问,最少需要多少步才能将所有车都放到主对角线上?
棋盘的主对角线是所有 ( i , i ) (i,i) (i,i) 的单元格,其中 1 ≦ i ≦ n 1≦i≦n 1≦i≦n 。
输入描述:
第一行包含测试用例数 T ( 1 ≦ T ≦ 10 3 ) T(1≦T≦10^3) T(1≦T≦103) 。接下来是 T T T 个测试用例的描述。
每个测试用例的第一行包含两个整数 n n n 和 m m m ,分别表示棋盘的大小和车的数量 ( 2 ≦ n ≦ 10 5 , 1 ≦ m < n ) (2≦n≦10^5,1≦m<n) (2≦n≦105,1≦m<n) 。接下来的 m m m 行,每行包含两个整数 x i x_i xi 和 y i y_i yi ,表示第 i i i 个车的位置,即该车位于 ( x i , y i ) ( 1 ≦ x i , y i ≦ n ) (x_i,y_i)(1≦x_i,y_i≦n) (xi,yi)(1≦xi,yi≦n) 。保证初始状态下没有两辆车互相攻击。
所有测试用例中 n n n 的总和不超过 10 5 10^5 105 。
输出描述:
对于每个测试用例,输出一个整数,表示将所有车放到主对角线上所需的最小步数。
可以证明一定存在可行方案。
示例1
输入:
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
输出:
1
3
4
2
说明:
前三个测试用例的可能移动方案:
- ( 2 , 3 ) → ( 2 , 2 ) (2,3)→(2,2) (2,3)→(2,2)
- ( 2 , 1 ) → ( 2 , 3 ) , ( 1 , 2 ) → ( 1 , 1 ) , ( 2 , 3 ) → ( 2 , 2 ) (2,1)→(2,3),(1,2)→(1,1),(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 ) (2,3)→(2,4),(2,4)→(4,4),(3,1)→(3,3),(1,2)→(1,1) (2,3)→(2,4),(2,4)→(4,4),(3,1)→(3,3),(1,2)→(1,1)
解题思路
本题核心是置换环结合并查集的图论模型求解最小移动步数。初始车辆互不攻击,意味着所有列坐标、行坐标各自唯一,可将每组坐标 ( x , y ) (x,y) (x,y) 抽象为映射关系,构成置换结构。使用并查集维护行列节点的连通性,统计两个关键值:ok 是本身已在主对角线( x = y x=y x=y)的车辆数,c 是合并时形成新置换环的次数。通过推导可得最小步数公式: m − o k + c m - ok + c m−ok+c。并查集搭配路径压缩,单次查询与合并均摊复杂度接近 O ( 1 ) O(1) O(1),可以高效应对 n ≤ 10 5 n\le10^5 n≤105、多组测试用例的数据约束。
总结
核心逻辑:把车辆位置转化为置换环模型,借助并查集统计自环数量与非自环置换环个数,代入公式直接计算答案。
关键操作:初始化并查集、合并每组坐标对应的行列节点、统计自环数与环数量、套用公式输出结果。
效率保障:路径压缩优化后的并查集运算极快,线性复杂度完美适配题目大数据范围。
代码简要说明
- 并查集基础:
fd函数实现带路径压缩的查找,u函数完成节点合并,同时统计自环数ok和置换环数c。 - 多组用例处理:每组测试用例先重置并查集、清零统计变量,再依次读取每辆车的坐标并执行合并。
- 公式计算:根据结论 m − o k + c m - ok + c m−ok+c 算出最小步数并输出,逻辑简洁且运行高效。
代码内容
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
typedef vector<vector<ll>> vvt;
typedef pair<ll,ll> pll;
const ll N=100010;
const ll INF=1e18;
const ll M=1e6+10;
const ll mod=1e9+7;
ll p[N];
ll fd(ll u){
if(p[u]==u) return u;
return p[u]=fd(p[u]);
}
ll c,ok;
void u(ll a,ll b){
if(a==b){ok++;return;}
ll ra=fd(a),rb=fd(b);
if(ra==rb) c++;
else p[rb]=ra;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
ll t; cin>>t;
while(t--){
ll n,m; cin>>n>>m;
c=0; ok=0;
for(ll i=1;i<=n;i++) p[i]=i;
for(ll i=1;i<=m;i++){
ll x,y; cin>>x>>y;
u(x,y);
}
cout<<m-ok+c<<endl;
}
return 0;
}
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)