【輸入數據】
第一行輸入兩個正整數m和n。
以下若干行每行四個正整數x1,y1,x2,y2,表示第x1行第y1列的點和第x2行第y2列的點已經有連線。輸入保證|x1-x2|+|y1-y2|=1。
【輸出數據】
輸出使得連通所有點還需要的最小花費。
【輸入樣例】
2 2
1 1 2 1
【輸出樣例】
3
時間限制
各測試點1秒
內存限制
你的程序將被分配32MB的運行空間
題解和數據 密碼:bjp5
本題是一個最小生成樹和並查集的結合體,具體思想看代碼及註解
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int m,n,tot=0,f[1000001];//此題關鍵是如何把二維轉換成一維,這樣才能用並茶几
void init();//m*n的矩陣轉成一維數組,共有m*n個元素,第i行j列的元素轉成一維後
int find(int);//對應於一位下標爲(i-1)*n+j,n表示矩陣共多少列
void merge(int,int);
void work();
int main()
{
init();
work();
return 0;
}
void init()
{
cin>>m>>n;
for(int i=1;i<=m*n;i++)f[i]=i;//並查集初始化
while(!cin.eof())//當未到文件結束
{
int x,y,x1,x2,y1,y2;
cin>>x1>>y1>>x2>>y2;
x=(x1-1)*n+y1;//把(x1,y1)轉到一維
y=(x2-1)*n+y2;
merge(x,y);//合併
}
}
void work()
{
int x,y;
for(int i=1;i<=n;i++)//先枚舉每一條縱邊,每列有m條縱邊
for(int j=1;j<=m-1;j++)//枚舉每條縱邊的起始端點
{
x=(j-1)*n+i;//縱邊的上端點
y=j*n+i;//縱邊的下端點
x=find(x);
y=find(y);
if(x!=y)//如果兩端點不在一個集合則總數+1,併合並
{
tot++;
merge(x,y);
}
}
for(int i=1;i<=m;i++)//枚舉每條橫邊
{
for(int j=1;j<=n-1;j++)
{
x=(i-1)*n+j;//衡邊的左端點
y=x+1;//右端點等於左端點+1
x=find(x);
y=find(y);
if(x!=y)//不在一個集合則總數+2,併合並
{
tot+=2;
merge(x,y);
}
}
}
cout<<tot<<endl;
}
int find(int x)
{
if(f[x]==x)return x;
f[x]=find(f[x]);
return f[x];
}
void merge(int x,int y)
{
x=find(x);
y=find(y);
f[y]=x;
}