CodeForces 1238E Keyboard Purchase(狀態壓縮dp)

 

 

大致題意:給你一個由最多m種字符構成的長度爲L的字符串。定義兩個相鄰字符的代價之差是兩個字符對應位置的絕對值,現在讓你找到這m種字符的一種排列方式,使得總的代價之和最小,問最小代價是多少。

很神奇的一種狀壓姿勢。

我們考慮最好的情況下肯定是讓任意兩個字符位置之差爲1,但是實際上相鄰的最多隻有兩個,不能所有的位置之差都爲1。但是我們在做的時候,可以維護當前可以取的最小距離。初始狀態令所有的字符之間最小距離都爲0,令狀態i表示哪些字符的位置已經確定了。如果一個字符位置確定而另一個未確定,那麼這兩個字符的最小距離就會加一,如果有c個字符對滿足條件,那麼總的最小距離就會增加c。如此我們令f[i]表示狀態i下,最小的總的最小距離,那麼有狀態轉移方程f[i]=min(f[i^(1<<j)]+c)。這個方程的含義相當於就是枚舉確定字符的順序。對於任意兩個字符a和b,a和b的最終距離你可以理解爲,從a確定到b確定兩個時刻之差。

感覺這麼說還是有點難以理解,對着代碼琢磨一下會更好。具體見代碼:

#include<bits/stdc++.h>
using namespace std;
int n,m,g[21][21],f[1048576];
char s[100010];
int main(){
    scanf("%d%d%s",&n,&m,s+1);
	for(int i=2;i<=n;++i)
		g[s[i-1]-'a'][s[i]-'a']++,g[s[i]-'a'][s[i-1]-'a']++;
	for(int i=1,c;i<(1<<m);++i){
        c=0;
		f[i]=0x3f3f3f3f;
		for(int j=0;j<m;++j)
			for(int k=j+1;k<m;++k)
				if((i>>j&1)^(i>>k&1))
					c+=g[j][k];
		for(int j=0;j<m;++j)
			if(i>>j&1)
				f[i]=min(f[i],f[i^(1<<j)]+c);
	}
	printf("%d\n",f[(1<<m)-1]);
}

 

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