题解
四根手指按四根弦,总共有4!=24种不同的按法,预处理所有的按法
对每种合法状态进行状态转移,路径是曼哈顿距离之和
太久没做dp,特么想多了。。。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e4+10;
const int INF=0x3f3f3f3f;
int n,m;
struct state{
int a[4],b[4];
void read(){
for (int i = 0; i <4; ++i) {
cin>>a[i]>>b[i];
}
}
}s[N];
int t[24][4];//保存4!种手指按法
void init(){
int A[4]={0,1,2,3};
for (int i = 0; i < 24; ++i) {
memcpy(t[i],A, sizeof(A));
next_permutation(A,A+4);
}
s[0]={0,0,0,0,1,2,3,4};//初始状态 0弦
}
bool legal(int* pos,int* finger){
for (int i = 1; i <4; ++i) {
if(pos[finger[i-1]] > pos[finger[i]])
//大序号的手指不可以大于小序号手指的位置
return false;
}
return true;
}
int cal(state A,state B,int* pre,int* nxt){
int res=0;
for (int i = 0; i <4; ++i) {
res+=abs(A.a[pre[i]]-B.a[nxt[i]]);
res+=abs(A.b[pre[i]]-B.b[nxt[i]]);
}
return res;
}
int dp[N][24];
int main(){
ios::sync_with_stdio(0);
init();
int T;
cin>>T;
for (int cs = 1; cs <= T; ++cs) {
printf("Case #%d:\n",cs);
cin>>n;
for (int i = 1; i <= n; ++i) {
s[i].read();
}
memset(dp, INF, sizeof(dp));
dp[0][0]=0;//初始状态合法
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <24; ++j) {
if(!legal(s[i].b,t[j])) continue;
for (int k = 0; k <24; ++k) {//中间转移状态
if(dp[i-1][k]==INF)continue;
dp[i][j]=min(dp[i][j],dp[i-1][k]+cal(s[i-1],s[i],t[k],t[j]));
}
}
}
int ans=INF;
for (int i = 0; i < 24; ++i) {
ans=min(ans,dp[n][i]);
}
printf("%d\n", ans);
}
return 0;
}