SOJ 2818_QQ音速
【题意】两只手,一次只能用一只手按一个键子(0,1,2,3),给出从i键到j键所需的消耗的体力,求依次按下一系列键子所需最小体力。
【分析】
法一:开一个三维数组,分别记录移动到位置及左右手按的键子。
状态转移方程;
v[k][i][j]=min(v[k-1][c[k-1]-'0'][j]+w[c[k-1]-'0'][i],v[k-1][i][c[k-1]-'0']+w[c[k-1]-'0'][j]);其中k取遍0.1.2.3
【代码】
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; const int maxn=1000050; int v[maxn][4][4]; int w[4][4]={{0,1,2,2},{1,0,1,1},{2,1,0,2},{2,1,2,0}}; int Min; char c[maxn]; const int INF=0x3fffffff; int main (void) { while(scanf("%s",c)==1) { Min=INF; int len=strlen(c); memset(v,10,sizeof(v)); for(int i=0;i<4;i++) for(int j=0;j<4;j++) v[0][i][j]=w[3][j]+w[2][i]; for(int k=1;k<len;k++) { for(int i=0;i<4;i++) { for(int j=0;j<4;j++) v[k][i][j]=min(v[k-1][c[k-1]-'0'][j]+w[c[k-1]-'0'][i],v[k-1][i][c[k-1]-'0']+w[c[k-1]-'0'][j]); } } for(int i=0;i<4;i++) { Min=min(v[len-1][i][c[len-1]-'0'],Min); Min=min(v[len-1][c[len-1]-'0'][i],Min); } printf("%d\n",Min); } return 0; }
法二:开一个二维数组,分别记录移动的次数及对于某一只手来说该次移动所按的键子(注意边界
状态转移方程:
对于j取遍0,1,2,3
当j==c[i-1]-'0'时
for(int k=0;k<4;k++)
v[i][j]=min(v[i][j],v[i-1][k]+w[k][c[i]-'0']);(j==c[i-1]-'0'
当j!=c[i-1]-'0时 v[i][j]=v[i-1][j]+w[c[i-1]-'0'][c[i]-'0'];
【代码】
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; const int maxn=1000050; int v[maxn][4]; int w[4][4]={{0,1,2,2},{1,0,1,1},{2,1,0,2},{2,1,2,0}}; int Min,len; char c[maxn]; const int INF=0x3fffffff; int main (void) { while(scanf("%s",c)==1) { Min=INF; len=strlen(c); for(int i=0;i<maxn;i++) for(int j=0;j<4;j++) v[i][j]=INF; v[0][2]=w[3][c[0]-'0']; v[0][3]=w[2][c[0]-'0']; for(int i=1;i<len;i++) { for(int j=0;j<4;j++) { if(j==c[i-1]-'0') { for(int k=0;k<4;k++) v[i][j]=min(v[i][j],v[i-1][k]+w[k][c[i]-'0']); } else v[i][j]=v[i-1][j]+w[c[i-1]-'0'][c[i]-'0']; } } for(int i=0;i<4;i++) Min=min(v[len-1][i],Min); printf("%d\n",Min); } return 0; }