1. 程式人生 > 遊戲 >橫版動作遊戲《密林傳奇》今日發售 支援中文

橫版動作遊戲《密林傳奇》今日發售 支援中文

我們需要選擇5個數,對於每一個數,不選就為0,選就為1
那麼對於5個數,我們就可以用5位的二進位制數來表示當前的狀態
這種將集合作為整數記錄狀態的一類演算法叫做狀態壓縮DP

在狀態壓縮中,二位用二進位制儲存,所以有一些常用的操作:
(1)空集φ:0
(2)只含有第i個元素的集合{i}:1<<i
(3)含有全部n個元素的集合{0,1,...,n-1}:(1<<n)-1
(4)判斷第i個元素是否屬於集合S:if(S>>i&1)
(5)向集合S中加入第i個元素S∪{i}:S|1<<i
(6)從集合S中移出第i個元素S{i}:S&~(1<<i)
(7)集合S和T的並集S∪T:S|T
(8)集合S和T的交集S∩T:S&T
此外,想要將集合S={0,1,...,n-1}表示的所有狀態枚舉出來,可以寫成:

for(int s=0;s<(1<<n);s++){
	//對子集的處理
}

例題

在這道題中,可以看到單詞數目很少,容易想到列舉所有的單詞連線情況,在判斷最大長度,但情況太多(\(n!\)),會超時

所以用狀態壓縮DP
\(f[i][j]\)表示已經連線到了單詞I,此時串的狀態為S
狀態用狀態壓縮,變成二進位制
狀態轉移方程:
\(f[i][j+s]=max(f[i][j]+length[s])\)


最大狀態為1111111111111111,轉換成二進位制就為65535,再加上1
狀態壓縮陣列就是:

int f[16][65536];

常數陣列:(只包含第i個單詞)

const int only[16]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};

邊界條件說明:狀態中只有一個單詞的情況:\(f[i][only[i]]=len[i]\);


條件判斷

if(only[i]&j){
//表示 “ 如果單詞i在狀態j中…”(注意:其實這裡的i指的是第i+1個單詞,下面一樣,因為編號從0開始)
}

總程式碼:

#include<bits/stdc++.h>
using namespace std;
const int only[16]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
int n;
char s[16][102];
int f[16][65536];
int len[16];
int work(int i,int j){
	int j1,temp;
	if(f[i][j]>0) return f[i][j];
	j1=j-only[i];//從狀態j中刪去i
	for(int k=0;k<n;k++)
		if(i!=k&&s[i][len[i]-1]==s[k][0]&&(only[k]&j)){//可以接龍
			temp=work(k,j1)+len[i];
			f[i][j]=max(f[i][j],temp);
		}
	return f[i][j];
}
int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		scanf("%s",s[i]);
		len[i]=strlen(s[i]);
	}
	for(int i=0;i<n;i++)
		f[i][only[i]]=len[i];
	int ans,temp;
	ans=0;
	for(int i=0;i<n;i++)\\從第i個單詞開始連
		for(int j=1;j<(1<<n);j++)
			if((only[i]&j)){
				temp=work(i,j);
				ans=max(ans,temp);
			}
	cout<<ans<<endl;
	return 0;
}

謝謝觀看
PS.