藍橋杯-算法提高(圖論):根據變換規則產生數

問題描述: 

給出一個整數 n(n<10^30) 和 k 個變換規則(k<=15)。

規則:一位數可變換成另一個一位數:規則的右部不能爲零。

  例如:n=234。有規則(k=2):

  2-> 5

  3-> 6

  上面的整數 234 經過變換後可能產生出的整數爲(包括原數):

  234

  534

  264

  564

  共 4 種不同的產生數

  問題:

  給出一個整數 n 和 k 個規則。

  求出:

  經過任意次的變換(0次或多次),能產生出多少個不同整數。


  僅要求輸出個數。
  輸入格式:
  n k
  x1 y1
  x2 y2
  ... ...
  xn yn
  輸出格式:
  一個整數(滿足條件的個數):

樣例輸入

234 2
2 5
3 6

樣例輸出

4

解題思路:

在變換規則中出現的數字轉換需要全部覆蓋,此處有點想排列組合,在可變的數字中選擇一寫進行變換,即

n=1223 ,變換規則爲2->4,那麼變換後產生的結果的可能有:

1423 1243 1443

而且變換的次數不受限制,所以在變換的過程中應當還要考慮到在變換後的基礎之上再進行變換,即

n=1334 ,變換規則爲1->4,4->2,那麼變換後產生的結果可能有:

4334 2334 4332 1332 2332

 

所以根據以上總結可以參考圖論中的Floyd算法:https://baike.baidu.com/item/Floyd算法/291990?fr=aladdin

然而該題並不是完全的跟floyd算法相同,在該題中只需要找到所有的變換規則(包括隱藏的變換股則,2->3,3->6,那麼2->6)

所以我們需要找到所有的從一個節點到其他幾點的可連通路,構建一個10✖10的有向圖,用1表示從一個點到另一個點可達,用0表示不可達。

算法步驟:

1.初始化有向圖,將最原始的有向邊用1表示出來,形成可連通路徑

2.找隱藏路徑,通過兩個連通的路徑並且中間節點相等,即可構成新的路徑

3.再遍歷原始數字,在有向圖中找出可以變換的數字的連通路徑數+1

4.將所有的連通數相乘即爲總的變換個數

關鍵點:從隱藏變換規則推到新的變換規則

用g[i][j]表示有向邊且不可達爲0,用s表示中間變換的數字,如果存在g[i][s]==1&&g[s][j]==1,說明從數字i通過中間數字s可以變換到數字j,所以g[i][j]=1

當然前提條件是i、j、s互不相等,即 i != j && j != s && i != s

 

從0-9,一個個開始找,用三層循環,一層表示開始數字,一層表示中間數字,一層表示變換後的數字,之後便可以找到所有的變換規則

完整代碼:

package generationNumber;

import java.text.NumberFormat;
import java.util.Scanner;

public class GenerationNumber {
	public static void main(String args[]){
		Scanner input = new Scanner(System.in);
		int ori_number = 0;//需要改變的數字
		int chan_number = 0;//改變後的數字
		String number = null;//原始數據
		int t;
		int can[][] = new int[10][10];//創建圖
		number = input.next();
		t = input.nextInt();	
		while (t--!=0){
			ori_number = input.nextInt();
			chan_number = input.nextInt();
			can[ori_number][chan_number] = 1; //初始化有向圖
		}
		for (int k = 0; k < 10; k++)
			for (int j = 0; j < 10; j++)
				for (int i = 0; i < 10; i++)
					if (i != j && j != k && i != k)
						if (can[i][k] == 1 && can[k][j] == 1)//創建新的變換規則
							can[i][j] = 1;
		double sum = 1;
		for (int i = 0; i < number.length(); i++){
			int n1 = number.charAt(i) - '0';
			int change = 1;
			for (int j = 0; j < 10; j++)//計算每一個變換數字的變換規則個數
				if (can[n1][j] == 1 && n1 != j)
					change++;
			sum *= change;//總的變換次數
		}
		NumberFormat nf = NumberFormat.getInstance();//格式化輸出,非科學技術表示
        nf.setMaximumFractionDigits(20);
        nf.setGroupingUsed(false);
		System.out.print(nf.format(sum));
		}

}

 

 

 

 

 

 

 

 

 

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