1. 程式人生 > 其它 >PTA—— 暢通工程之區域性最小花費問題

PTA—— 暢通工程之區域性最小花費問題

技術標籤:我的c++程式碼合集c++

目錄

題目來源

1.PTA—資料結構與演算法題目集(中文)—程式設計題—7-50 暢通工程之區域性最小花費問題 (35分)

2.網址:https://pintia.cn/problem-sets/15/problems/897

題目內容

某地區經過對城鎮交通狀況的調查,得到現有城鎮間快速道路的統計資料,並提出“暢通工程”的目標:使整個地區任何兩個城鎮間都可以實現快速交通(但不一定有直接的快速道路相連,只要互相間接通過快速路可達即可)。現得到城鎮道路統計表,表中列出了任意兩城鎮間修建快速路的費用,以及該道路是否已經修通的狀態。現請你編寫程式,計算出全地區暢通需要的最低成本。

輸入格式:
輸入的第一行給出村莊數目N (1≤N≤100);隨後的N(N−1)/2行對應村莊間道路的成本及修建狀態:每行給出4個正整數,分別是兩個村莊的編號(從1編號到N),此兩村莊間道路的成本,以及修建狀態 — 1表示已建,0表示未建。

輸出格式:
輸出全省暢通需要的最低成本。

輸入樣例:
4
1 2 1 1
1 3 4 0
1 4 1 1
2 3 3 0
2 4 2 1
3 4 5 0
輸出樣例:
3

我的答案(c++)

#include <iostream>
#include <climits>
using namespace std;
#define max INT_MAX
class town { public: int townnumber;//村莊數量 int money [101][101];//兩個村莊修路錢 int minmoney;//最少錢 protected: int connect[101];//村莊連通狀態 連通:-1 未連通:最少修路錢 public: void input()//輸入資料 { int i,t1,t2,m,s; cin>>townnumber; for (i=0;i<townnumber*(townnumber-1)/2;i++) { cin>>t1; cin>>
t2; cin>>m; cin>>s; if (s==0) { money[t1][t2]=m; money[t2][t1]=m; } else { money[t1][t2]=0; money[t2][t1]=0; } } findminmoney(); } protected: int findmintown()//找最少錢的村莊路 { int min=max,flag=-1,i; for (i=1;i<=townnumber;i++) { if (min>connect[i]&&connect[i]!=-1) { flag=i; min=connect[i]; } } return flag; } void findminmoney()//找最少錢 { minmoney=0; int t1=1,t2,i; connect[1]=-1; for (i=2;i<=townnumber;i++) { connect [i]=money[1][i]; } for (i=2;i<=townnumber;i++) { t2=findmintown(); minmoney+=connect[t2]; connect[t2]=-1; for (int j=2;j<=townnumber;j++) { if (money[t2][j]<connect[j]) { connect[j]=money[t2][j]; } } } } }; int main() { struct town t1; t1.input(); cout<<t1.minmoney<<endl; return 0; }

相似題目

去掉輸入N(N−1)/2行的條件,沒有輸入對應關係的村莊預設村莊之間的路不可能修成

我的程式碼:

#include <iostream>
#include <climits>
#include <fstream>
using namespace std;
#define max INT_MAX
class town
{
public:
	int townnumber;//村莊數量 
	int money[101][101];//兩個村莊修路錢
	int minmoney;//最少錢 
protected:
	int connect[101];//村莊連通狀態 連通:-1 未連通:最少修路錢 
public:
	void input()//輸入資料
	{
		int i, t1, t2, m, s;
		cin >> townnumber;
		for (i = 0; i<townnumber*(townnumber - 1) / 2; i++)
		{
			cin >> t1;
			cin >> t2;
			cin >> m;
			cin >> s;
			if (s == 0)
			{
				money[t1][t2] = m;
				money[t2][t1] = m;
			}
			else
			{
				money[t1][t2] = 0;
				money[t2][t1] = 0;
			}
		}
		findminmoney();
	}
	void inputtest()
	{
		ifstream ifs;
		ifs.open("test02.txt", ios::in);
		if (!ifs.is_open())
		{
			cout << "失敗" << endl;
			return;
		}
		int i, j, t1, t2, m, s, inputnumber;
		ifs >> townnumber;
		ifs >> inputnumber;
		for (i = 1; i <= townnumber; i++)
		{
			for (j = 1; j <= townnumber; j++)
			{
				money[i][j] = 1000;
			}
		}

		for (i = 0; i < inputnumber; i++)
		{
			ifs >> t1;
			ifs >> t2;
			ifs >> m;
			ifs >> s;
			if (s == 0)
			{
				money[t1][t2] = m;
				money[t2][t1] = m;
			}
			else
			{
				money[t1][t2] = 0;
				money[t2][t1] = 0;
			}
		}
		findminmoney();

	}
protected:
	int findmintown()//找最少錢的村莊路 
	{
		int min = max, flag = -1, i;
		for (i = 1; i <= townnumber; i++)
		{
			if (min>connect[i] && connect[i] != -1)
			{
				flag = i;
				min = connect[i];
			}
		}
		return flag;
	}

	void findminmoney()//找最少錢 
	{
		minmoney = 0;
		int t1 = 1, t2, i;
		connect[1] = -1;
		for (i = 2; i <= townnumber; i++)
		{
			connect[i] = money[1][i];
		}
		for (i = 2; i <= townnumber; i++)
		{
			t2 = findmintown();
			minmoney += connect[t2];
			connect[t2] = -1;
			for (int j = 2; j <= townnumber; j++)
			{
				if (money[t2][j]<connect[j])
				{
					connect[j] = money[t2][j];
				}
			}
		}
	}
};
int main()
{
	struct town t1;
	t1.inputtest();
	cout << t1.minmoney << endl;
	system("pause");
	return 0;
}

演算法簡述

一.程式碼實現

思想:從村莊1開始找修路所需最少錢的村莊2,再找通往村莊1/2修路所需最少錢的村莊3,繼續找通往1/2/3所需最少錢的村莊4……以此類推直到所有村莊連通為止。

二.各變數含義

1.townnumber :村莊數量
2.money[i][j]: 村莊i和村莊j修路所需要的錢
3.minmoney: 橋樑最少預算
4. connect[i]:村莊連通狀態( i村莊已連通:值為-1 i村莊未連通:i村莊通往已連通村莊所需最少的修路錢 )
5. inputnumber:輸入的資料行數,即給出的村莊關係個數

三.函式功能

1.void input()

輸入村莊i和村莊j修路所需要的錢(嚴格符合原題的輸入程式,需要完整輸入已知村莊所有道路連通狀況)(資料通過鍵盤輸入)

具體實現

(1)鍵盤讀取給townnumber賦值
(2)鍵盤讀取給money[i][j]賦值,如果已經修路,則money為0,如果沒有修路,則money如實填寫
(3)執行findmoney()函式給minmoney賦值

2.void inputtest()
和void input()一樣,不過它符合修改後題目要求,可以不輸完所有村莊對應關係,沒輸入的村莊關係預設此路不通(資料通過檔案輸入)

具體實現

(1)文件讀取給townnumber,inputnumber賦值
(2)文件讀取給money[i][j]賦值,如果已經修路,則money為0,如果沒有修路,則money如實填寫,對於沒有輸入的村莊關係,money為一個很大的值
(3)執行findmoney()函式給minmoney賦值

3.int findmintown() :

找未連通村莊與已連通村莊之間最少錢的那條路

具體實現

(1)找出connect中除去-1外最小的數(即找最少的錢)
(2)返回最小數的下標(即返回最少錢的村莊編號)

4.void findminmoney()

計算最少的橋樑預算

具體實現

(1)從村莊1(t1)開始算,用connect陣列記錄各村莊通往t1所需花費,其中t1村莊通往t1村莊的connect[t1]記為-1
(2)利用findmintown函式找出通往村莊t1所需最少錢的村莊t2並用minmoney記錄該錢
(3)connect[t2]計為-1,用connect記錄通往村莊t1和村莊t2所需的最少錢(即t2到i村莊的錢比t1到i村莊的錢更少時把connect[i]的值替換成更便宜那個即替換成money[t2][i])並加到minmoney中
(4)利用findmintown函式找出通往村莊t1和t2所需最少錢的村莊t3
(5)connect[t3]計為-1,用connect記錄通往村莊t1,t2,t3所需的最少錢(即t3到i村莊的錢比connect[i]中的錢更少時把connect[i]的值替換成更便宜那個即替換成money[t3][i])並加到minmoney中
(6) 依次類推,直到connect中所有值為-1(即所有村莊已連通)為止
(7)返回minmoney

5.main()
建立村莊集合並列印最少預算

具體實現
(1)建立村莊部落t1
(2)利用t1.inputtest()/t1.input()輸入村莊資料
(3)列印最少預算

四.如何使用

1.鍵盤輸入且嚴格符合原題:建立村莊部落並呼叫input()函式,再列印minmoney即可。

輸入格式:第一行給出村莊數N(1<=N<=100),隨後的N(N-1)/2行給出村莊名,修路成本,修建狀態——村莊a編號 村莊b編號 村莊a和村莊b之間道路成本 修建狀態(1為已建,0為未建),資料間以空格分隔

輸出格式:輸出的那個數即為最低成本

2.文件輸入且符合修改後題目:建立符合輸入格式的文件並修改原始檔第41行程式碼的路徑為待測試文件路徑。main函式中建立村莊部落並呼叫inputtest()函式,再列印minmoney即可。

文件輸入格式:第一行給出村莊數N(1<=N<=100)和輸入的資料行數M,隨後的M行給出村莊名,修路成本,修建狀態——村莊a編號 村莊b編號村莊a和村莊b之間道路成本 修建狀態(1為已建,0為未建),資料間以空格分隔

輸出格式:輸出的那個數即為最低成本

碎碎念

今天是2020.1.12,這是我們機器人三輪考核的題目,也是我第一個自己寫的c++程式碼,還是挺有紀念意義的。現在的我還是大一上冊,所以還沒學演算法和資料結構,好像這題是資料結構的經典例題,但是我還沒學到所以我這個是按照自己想法寫的,沒有用到演算法,不過我看用演算法好像很簡單啊,只有四五十行的樣子,嗚嗚嗚我記得我第一次寫的版本是一百多行的,這已經是我優化以後最短的版本了。

分享一點小插曲吧,本來學長髮到群裡的考核題就是PTA原題的截圖,因為PTA輸入的是所有村莊的修路關係,所以我本來的思路是從路出發,根據輸入一條條路來決定要建還是不要建。但在我寫的差不多的時候一看學長給的測試資料,感覺不是很對,那個測試資料有20個村莊但是隻有短短的二十幾行,按理說應該是有20*19/2=190行資料才對的,於是我果斷剎車換思路變成了現在的從村莊出發來判斷。幸好我換思路了,因為後來我和學長理論說他的資料不符合題目要求的時候他很霸氣的說:“那就把題目條件改了”順帶一句“我這個資料更符合實際情況,因為現實中不是所有村莊的路都可以建成的。”嗯嗯嗯,你說得都對,刪條件都這麼理直氣壯。

不過不得不說我c++真的是菜菜的,因為我語法都還沒學完呢就要寫這個c++考核試題,學長群裡發的那個測試資料的檔案我都是手動輸入的,然後本人又手殘經常輸錯從頭開始輸(我那個devcpp按了回車後就不能刪除回車前輸的資料了),然後被學長敲了一頓讓我學用ifstream ofstream,然後我百度了半天,嗯……還是不會,最後只能依葫蘆畫瓢套了一個輸入模板上去,所以它限制挺多的,我現在只會用txt測所以我把學長那個csv檔案手動轉成txt測的資料,假裝自己會了ifstream交的這個作業,嗯……我貌似還忘了關閉檔案,但不管了不管了能用就行,等我以後學到ifstream再說。

第一個程式碼再PTA上是答案正確的,第二個我不知道我嚴不嚴謹哦,反正學長給我是測試樣例我都是能通過的。嗯還有我第二個是用VS2015寫的,不知道其他版本的編譯器能不能執行,因為學長之前用VS2017寫的程式碼我就不能用VS2015執行。

至於為什麼用VS2015……因為我不會裝VS,我也沒有電腦,機器人裡面的電腦只有VS2015的編譯器,所以我剛開始用的就是2015版本,後來用習慣了就一直都用2015了(其實是因為新版本不會用)

哦還有上面那個演算法簡述是我交給學長的演算法報告的修改版,第一次寫演算法報告我好懵啊,不知道寫什麼也沒有模板,語言也不太嚴謹,僅供參考,僅供參考。