Submit your solution Discuss this problem Best solutions |
Description
最近flymouse开始玩qq音速,这个游戏只需要按4个键,上,下,左,右(分别用u,d,l,r表示)。 flymouse必须按照游戏规则,依次按下一系列键。问题是flymouse的手太胖了,他只能把两个手指放在方向键上。 flymouse把一个手指从键i移动到键j,要耗费w[i][j]的体力,而按键不需要耗费体力。 由于flymouse反应比较慢,所以他每次只能移动一个手指。现在可怜的flymouse问你,他最少耗费多少体力? 假设flymouse一开始就把手指放在左、右两个键上。 下面是w[i][j]数组 u d l r u 0 1 2 2 d 1 0 1 1 l 2 1 0 2 r 2 1 2 0Input
本题有多组测试数据,请处理到EOF 每组数据仅一行,为一个仅由0,1,2,3组成的串,表示flymouse需要依次按下的键 串的长度不超过10^6 0,1,2,3 分别代表 u,d,l,rOutput
对每组输入,输出flymouse耗费的最少体力Sample Input
01230123Sample Output
8Source
Felicia @ WHU
同黑书上的舞蹈家
状态:
d[i][j]表示第i次按键停留在j键上的最小体力耗费
状态转移方程:
d[i][j]=d[i-1][j]+w[s[i-1]][s[i]] (j!=s[i-1])
d[i][j]=min{d[i-1][k]+w[k][s[i]]} (j==s[i-1],0<=k<4)
边界:
d[0][2]=w[3][s[0]]
d[0][3]=w[2][s[0]]
也可贪心,考虑到第i次按键后应停留在s[i]键上最优,
所以只需要记录每次按键后,两个手指最优停留位置
DP
//DP代码是别人的
#include<iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
char a[1000001];
int d[1000001][4];
int w[4][4]={0,1, 2, 2 , 1 ,0 ,1, 1 , 2, 1 ,0 ,2 , 2 ,1 ,2 ,0};
int answer;
int main()
{
int len,i,j,s;
while(scanf("%s",a)==1)
{
len=strlen(a);
memset(d,10,sizeof(d));
for(i=0;i<4;i++)
{
if(i==2)
d[0][i]=w[3][a[0]-'0'];
else if(i==3)
d[0][i]=w[2][a[0]-'0'];
}
for(i=1;i<len;i++)
for(j=0;j<4;j++)
{
if(j!=a[i-1]-'0')
{
d[i][j]=d[i-1][j]+w[a[i-1]-'0'][a[i]-'0'];
}
else
{
for(s=0;s<4;s++)
{
if(d[i-1][s]+w[s][a[i]-'0']<d[i][j])
d[i][j]=d[i-1][s]+w[s][a[i]-'0'];
}
}
}
answer=10000000;
for(i=0;i<4;i++)
{
if(d[len-1][i]<answer)
answer=d[len-1][i];
}
printf("%d/n",answer);
}
return 0;
}
贪心
#include<cstdio>
int w[4][4]={0,1,2,2,1,0,1,1,2,1,0,2,2,1,2,0};
char s[1000005];
int main()
{
while(scanf("%s",s)==1)
{
int i,j,t,a=2,b=3,ans=0;
for(i=0;s[i];i++)
{
t=s[i]-48;//第i个按键
if(w[a][t]<w[b][t])//a转换到t最优
{
ans+=w[a][t];
a=t;
}
else if(w[a][t]>w[b][t])//b转换到t最优
{
ans+=w[b][t];
b=t;
}
else//相同
{
for(j=i+1;s[j];j++)
if(s[j]-48==a||s[j]-48==b)
break;
if(s[j]-48==b)//后面有b,保留b,把a转换到t
{
ans+=w[a][t];
a=t;
}
else
{
ans+=w[b][t];
b=t;
}
}
}
printf("%d/n",ans);
}
}