Sdut 1008 最長公共子序列(n個字符串的最大公共字串)

Description

從一個給定的串中刪去(不一定連續地刪去)0個或0個以上的字符,剩下地字符按原來順序組成的串。例如:“ ”,“a”,“xb”,“aaa”,“bbb”,“xabb”,“xaaabbb”都是串“xaaabbb”的子序列。(例子中的串不包含引號。)
 
編程求N個非空串的最長公共子序列的長度。限制:2<=N<=100;N個串中的字符只會是數字0,1,…,9或小寫英文字母a,b,…,z;每個串非空且最多含100個字符;N個串的長度的乘積不會超過30000。

Input

文件第1行是一個整數T,表示測試數據的個數(1<=T<=10)。接下來有T組測試數據。各組測試數據的第1行是一個整數Ni,表示第i組數據中串的個數。各組測試數據的第2到N+1行中,每行一個串,串中不會有空格,但行首和行末可能有空格,這些空格當然不算作串的一部分。

Output

輸出T行,每行一個數,第i行的數表示第i組測試數據中Ni個非空串的最長公共子序列的長度。

Sample

Input

1
3
ab
bc
cd

Output

0

解題思路:做過兩個字符串的Lcs,這個題就是多維的Lcs問題,如何將多維轉爲一維是這個題的難點,在網上看了看,都是設置一個index用來標識多個字符串的不同長度形態,即每組不同長度的字符串都有一個唯一標誌數字,這就將多維轉化爲一維,然後開始從後向前遍歷,詳細看代碼:

package cn.wy.sdut.dp;

import java.util.Arrays;
import java.util.Scanner;

//這組肯定爆
//1234567890abcdefghijkhlmnopqrstuvwxyz09876543321xyzuvwopqrstabcdefghiljklmnopqrstuvwxyz
//09876543321xyzuvwopqrstabcdefghiljklmnopqrstuvwxyz1234567890abcdefghijkhlmnop
//12354567897dkfjlsdjlsjflsjdl
public class Main {
	
	static String[] s = new String[110];  //字符串數組
	static int[] dp = new int[300100]; // 狀態數組, 很奇怪,c++不會爆數組,java不定個大點的就爆了
	static int[] len = new int[110];  // 字符串長度
	static int n;
	
	public static int lcs(int[] tem) {
		int index, i, j, ans;
		
		// 如果有字符串長度爲0, 則返回0
		for(i=0; i<n; i++) {
			if(tem[i] == 0) return 0; 
		}
		
		// 建立映射
		for(index = tem[n-1] -1, i=n-1; i>=0; i--) {
			index = index*len[i] + tem[i] -1;
			System.out.println("index+"+i+":"+index);
		}
		
		//記憶化搜索
		if(dp[index] >= 0) return dp[index];
		
		//判斷是否所有串最後的字符都想等
		for(i=1; i<n; i++) {
			if(s[i].charAt(tem[i] - 1) != s[0].charAt(tem[0] - 1))  break;
		}
		
		//如果最後的字符相同, 最大長度 +1,之後恢復字符串長度,方便下次遍歷
		if(i >= n) {
			for(j=0; j<n; j++) {
				tem[j]--;
			}
			ans = lcs(tem) + 1;
			for(j=0; j<n; j++) {
				tem[j]++;
			}
		} else {  //否則,挨個枚舉,求最大值
			ans = 0;
			for(j=0; j<n; j++) {
				tem[j]--;
				int t = lcs(tem);
				ans = Math.max(t, ans);
				tem[j]++;
			}
			
		}
		
		dp[index] = ans;
		return ans;
	}
	
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		
		int t = scan.nextInt();
		for(int t1=0; t1<t; t1++) {
			n = scan.nextInt();
			
			int[] tem = new int[110];   //臨時數組,記錄臨時字符串長度
			for(int i=0; i<n; i++) {
				s[i] = new String();
				s[i] = scan.next();
				len[i] = tem[i] = s[i].length();
			}
			
			Arrays.fill(dp, -1);
			System.out.println(lcs(tem));
		}
		scan.close();
	}
}

 

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