連接格點

有一個M行N列的點陣,相鄰兩點可以相連。一條縱向的連線花費一個單位,一條橫向的連線花費兩個單位。某些點之間已經有連線了,試問至少還需要花費多少個單位才能使所有的點全部連通。

【輸入數據】

    第一行輸入兩個正整數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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章