题目:给定一个 n * n 的棋盘,棋盘中有 m 个棋子(m < n),每个棋子都在不同的行和列,且每个棋子都可以进行水平和竖直方向的移动(移动过程中也要保证每个棋子都在不同的行和列),求最少移动多少次才能使得每个棋子位于棋盘的主对角线上。题目
主要思路:当棋盘中放入棋子时,只有当棋子的坐标与之前放置的棋子坐标形成环路时,我才需要移动两步,否则只需要移动一步或者0步(恰好就在对角线上)
因此可以转换为一个动态规划问题 res += 2 if 形成环路 ; res = res if 放置在对角线上;res += 1 if 没有形成环路
对于环路判断可以使用并查集(新知识点)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int t, m, n;
int p[N];
int find(int x) {
if (x != p[x]) p[x] = find(p[x]);
return p[x];
}
int main() {
cin >> t;
while (t--) {
cin >> n >> m;
for (int i = 1; i <= n; i++) p[i] = i;
int res = 0;
for (int i = 1; i <= m; i++) {
int x, y;
cin >> x >> y;
if (x == y) continue;
else {
int px = find(x), py = find(y);
if (px == py) {
res += 2;
} else {
res += 1;
p[x] = y;
}
}
}
cout << res << endl;
}
return 0;
}