1. 程式人生 > 其它 >keepalive和腦裂問題

keepalive和腦裂問題

題目如下:



解題思路:

這道題本質上很簡單,只需要列舉該圖中所有節點的全排列並一一計算頻寬,最終找到頻寬最小且字典序最小的排列即可。這道題的難點在於:如何去接收輸入(這裡就不詳細介紹,直接看程式碼即可),怎麼進行頂點的去重(可以使用集合進行去重,還能求得頂點的個數(集合的長度),將集合再賦值給一個數組即可(目的是方便求兩個頂點的頻寬,直接用i,j充當下標遍歷排列中的頂點即可))。求頻寬是這裡的重點,實際上就是將排列中且在圖中也相連的兩個頂點的下標進行相減即可。這裡可以運用一個二重迴圈,外迴圈用於遍歷每一個頂點,內迴圈用於遍歷除了該頂點以外剩餘的頂點。並且假設B和G相連,那麼求BG的頻寬實質上也是在求GB的頻寬。因此,求頻寬的時候只需從左往右依次去求每個頂點的頻寬即可。(這裡的操作直接看程式碼即可,不懂的話再好好想想~)這裡運用了剪枝操作,具體如何剪枝請看程式碼,程式碼中都添加了註釋。關於如何實現全排列操作,這裡引用了庫中的next_permutation()函式。


程式碼如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
using namespace std;
int Matrix[26][26];        //定義鄰接矩陣
set<int> permutation;      //定義用於儲存排列變數的集合
int  nowpermutation[8];     //定義用於儲存排列的陣列
char minpermutation[8];     //定義用於儲存頻寬最小的排列的陣列
string inputstring;         //定義用於接收輸入的字串的變數

void dfs() {               //代表進行搜尋頻寬的函式dfs
	int length = permutation.size();                            //代表儲存當前集合長度的變數
	int minbandwidth = 0x3f3f3f3f;                              //定義儲存整道題中所有排列中的最小頻寬,即最終結果
	int i, j,flag=1;
	set<int>::iterator p = permutation.begin();
	for (p,i=0;p!=permutation.end(); i++,p++) {                 //將集合中的排列轉移到陣列上
		nowpermutation[i] = *p;
	}
	do {
		int maxbandwidth = 1;                                       //定義儲存整個排列中的最大頻寬
		for (i = 0; i < length; i++) {
			for (j = i + 1; j < length; j++) {                      //j從i+1開始,因為ji(ji)這兩個頂點的頻寬已經從之前的迴圈中求完了
				if (Matrix[nowpermutation[i]][nowpermutation[j]] == 1) {
					maxbandwidth = max(maxbandwidth, j - i);         //計算某一個節點的頻寬,如果比當前最大的頻寬大,那麼就進行更改,使其成為整個圖的頻寬。其中 j-i 代表計算兩個點的頻寬
					if (maxbandwidth > minbandwidth) {               //如果當前排列的頻寬已經大於整道題中的最小帶寬了,證明這個排列再往下執行都沒有作用,因此我們需要進行剪枝操作
						flag = 0;
						break;
					}
				}
			}
			if (flag == 0) {
				break;
			}
		}
		if (flag == 1) {
			if (minbandwidth != maxbandwidth) {                              //如果當前排列的頻寬已經等於整道題中的最小頻寬的話,那麼就證明我之前已經有一個排列的頻寬等於當前排列的帶寬了,那麼就保留之前的排列(選擇字典序最小的排列)
				minbandwidth = min(minbandwidth, maxbandwidth);
				for (i = 0; i < length; i++) {
					minpermutation[i] = nowpermutation[i] + 65;              //進行頻寬最小的排列賦值
				}
			}
		}
		flag = 1;
	} while (next_permutation(nowpermutation, nowpermutation + length));
	for (i = 0; i < length; i++) {
		cout << minpermutation[i] << " ";
	}
	cout << "->" << " " << minbandwidth << endl;

}
int main() {
	int i, j;
	char start, end;                                      //代表儲存起始頂點和終止頂點的變數  
	while (true) {
		memset(Matrix, 0, sizeof(Matrix));                //將鄰接矩陣的各個變數都初始化為0
		permutation.clear();
		cin >> inputstring;
		if (inputstring == "#") {
			return 0;
		}
		else {
			for (i = 0; i < inputstring.size(); i++) {
				if (inputstring[i] == ';') {
					continue;
				}
				else if (inputstring[i] == ':') {
					j = i;
					while (inputstring[++j] != ';') {
						end = inputstring[j];
						Matrix[start-65][end-65] = 1;
						Matrix[end-65][start-65] = 1;
						if (j == inputstring.size() - 1) {
							break;
						}
					}
				}
				else {
					start = inputstring[i];
					permutation.insert(inputstring[i]-65);
				}
			}
			dfs();           //求頻寬
		}
	}
}