您的位置:首页 > 其它

You Win! 状态压缩dp

2014-04-03 22:57 141 查看




题目大意:

有三种操作:(每个1步)

1.A-Z的字母,按up或down来改变大小,down A-Z up Z-A

2.左右移动cursor逐个字母移动

3.按FIRE确认

求一串字母(最多18个)最少要多少步?

题目地址:传送门

源码:

#include <stdio.h>
#include <string.h>

const int N=19;
int bt
,dist[26][26];
int dp[1<<N]
;//表示每位完成状态是i,光标在j的最小步数
#define inf 0x3f3f3f3f

inline void swap(int &a,int &b){
a=a^b;b=a^b;a=a^b;
}
inline int min(int a,int b){
return a>b?b:a;
}

int moveCursor(int from,int to,int state){
int rst=0;
if(from>to) swap(from,to);
for(int i=from;i<to;i++)
if(state&bt[i]) rst++;
return rst;
}

void solve(char *str){
int n=strlen(str),state=bt
;
//初始化状态
for(int i=0;i<state;i++){
for(int j=0;j<=n;j++)
dp[i][j]=inf;
}
for(int i=0;i<n;i++)
dp[0][i]=0;
for(int i=0;i<n;i++)
dp[bt[i]][i+1]=dist[str[i]-'A'][0]+1;

//状态转移--从dp[ss][j]-->dp[s][i]
for(int s=1;s<state;s++){
for(int i=1;i<=n;i++){
if((s&bt[i-1])==0) continue;
int ss=s^bt[i-1];
for(int j=1;j<=n;j++){
if((ss&bt[j-1])==0) continue;
dp[s][i]=min(dp[s][i],dp[ss][j]+dist[str[i-1]-'A'][str[j-1]-'A']+moveCursor(j,i,ss)+1);
}
}
}
int ans=inf;
for(int i=1;i<=n;i++)
ans=min(ans,dp[state-1][i]);
printf("%d\n",ans);
}

int getDist(int dest,int source){
int up=(source-dest+26)%26;
int down=(dest-source+26)%26;
return min(up,down);
}

void init(){
bt[0]=1;
for(int i=1;i<N;i++)
bt[i]=bt[i-1]*2;
for(int i=0;i<26;i++){//得到字母间最小转换步骤
for(int j=0;j<26;j++)
dist[i][j]=getDist(i,j);
}
}

int main(){
init();
char str
;
while(~scanf("%s",str)&&str[0]!='0')
solve(str);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: