题目描述
有一个M行N列的点阵,相邻两点可以相连。一条纵向的连线花费一个单位,一条横向的连线花费两个单位。某些点之间已经有连线了,试问至少还需要花费多少个单位才能使所有的点全部连通。
输入格式 Input Format
第一行输入两个正整数m和n。
以下若干行每行四个正整数x1,y1,x2,y2,表示第x1行第y1列的点和第x2行第y2列的点已经有连线。输入保证|x1-x2|+|y1-y2|=1。
输出格式 Output Format
输出使得连通所有点还需要的最小花费。
样例输入 Sample Input
2 2
1 1 2 1
样例输出 Sample Output
3
时间限制 Time Limitation
3s
注释 Hint
数据规模
m,n<=1000
来源
matrix67 系列模拟赛
好久没做图论题,心血来潮写一写,我们不难发现,对于一个不存在已有边的矩阵,肯定是连完纵向边,每行连一条横向边这样贪心最优,那么存在已有边时,我们考虑用并查集维护,同时用上述方法贪心,不过我们考虑一下,连完后的图的性质,一定是一条有n * m个点,n * m-1条边的树,同时,这棵树依题意满足权值最小,那么就是一颗最小生成树,再回想刚才的贪心做法,其实和最小生成树无异,那么我们不用费心思去改良之前的贪心,直接用Kurskal算法贪心,跑一边最小生成树。
同时,我们建树时需要手动给点标号,并且标号最大有n*m,所以不能很好地判断自己手动建边时是否存在已有边,因此存在重边,也就是边总数最差为2e6,数组大小记得开够。
当然,个人觉得写一个好一点的哈希似乎还是可以查询的,至于怎么写就要看大佬们的了。
还有,读入的是按m,n读入的,当时没看清,被这个卡了…
#include<bits/stdc++.h>
#define N 1001
#define gtc() getchar()
#define INF 0x3f3f3f3f
#define rg register
#define MAXN 5000010
#define ll long long
using namespace std;
template <class T>
inline void read(T &s){
T w = 1, ch = gtc(); s = 0;
while(!isdigit(ch)){if(ch == '-') w = -1; ch = gtc();}
while(isdigit(ch)){s = s * 10 + ch - '0'; ch = gtc();}
s = s * w;
}
struct node{
int x, y, z;
}d[MAXN];
int n, m, cnt = 0;
inline void add(int x, int y, int z){
d[++cnt].x = x, d[cnt].y = y, d[cnt].z = z;
}
int fa[MAXN];
inline int getfa(int x){
return fa[x] == x ? x : fa[x] = getfa(fa[x]);
}
bool cmp(node a, node b){
return a.z < b.z;
}
inline int point(int x, int y){//计算点的标号用的,手推一下就出来了
return y + (x-1) * n;
}
int main()
{
read(m), read(n);
int all = n * m;
for(int i = 1; i <= all; ++i) fa[i] = i;
for(int i = 1; i <= m; ++i)
for(int j = 1; j <= n; ++j){
int x = point(i, j), y;
if(i + 1 <= m){
y = point(i+1, j);
add(x, y, 1);
}
if(j + 1 <= n){
y = point(i, j+1);
add(x, y, 2);
}
}
int x, y, xx, yy;
while(~scanf("%d %d %d %d", &x, &y, &xx, &yy)){
int tx = point(x, y), ty = point(xx, yy);
add(tx, ty, 0);
}
sort(d + 1, d + cnt + 1, cmp);
int ans = 0;
for(int i = 1; i <= cnt; ++i){
x = d[i].x, y = d[i].y;
xx = getfa(x), yy = getfa(y);
if(xx == yy) continue;
fa[xx] = yy;
ans += d[i].z;
}
printf("%d\n", ans);
return 0;
}