一般而言规划题目侧重于思路,shortest path 也和规划一样需要建边,规划需要dag图,最短路只需要构成图即可,然后上单源最短路算法即可,实现上可能比较复杂。
例如本题目而言,首先看状态设计,d[i][j][s],代表前i个已经上电梯或已经到达,当前在i层,电梯内人员情况(空位和要到达楼层)
每个状态都可以往任意楼层走,然后上下乘客,但状态之间可能来回走来走去,可用dijstra算法。
进一步分析,当前只能最多只能去5个楼层,即电梯内乘客想去的楼层,或者下一位乘客起始楼层。到这五个楼层必然会有乘客的上下,这样便是DAG图(简单分析一下,不会走到原来的状态,便是DAG图)
那么S可能有多少种呐?
int cnt = 0;
for(int i= 0 ;i<=9;i++)
for(int j=i;j<=9;j++)
for(int k=j;k<=9;k++)
for(int g =k;g<=9;g++)
cout<<i<<j<<k<<g<<endl , cnt++;
cnt值为715,总共的状态715*10 * 2000为 1400万左右,单实际用到的状态很少,不是所有状态都可达到,实际使用状态在百万左右,这样乘上状态转移代价为5实际为百万级算法代价,加上使用map大概千万级的计算量
参考别人的算法,也有使用只记录前三个上电梯的人,因为第四个人只要上了,电梯我们只能选择去送其中一个人。这样电梯内总不会多于3个人。
对于自己的代码,使用map,要十分注意的是,对任意一个状态,开始要先上下乘客(因为这样做总是合算的),对原来的s要先保存下来,因为这个WRONG了两次
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
#include<string>
using namespace std;
const int inf = 21474836;
const int maxn =2005;
const int F = 10;
map<string,int>d[maxn][10];
int start[maxn] , dest[maxn];
int n;
int dp(int i,int j,string s){
if(d[i][j].count(s)) return d[i][j][s];
d[i][j][s] = inf;
string os = s;
for(int k = 0; k<4;k++){
int flo = s[k] -'0';
if(flo == j) s[k]='0';
}
int pos = i + 1;
for(int k=0;k<4;k++){
int flo = s[k] -'0';
if(pos <= n && flo == 0 && start[pos] == j) s[k] = '0' + dest[pos] , ++pos;
}
if(i == n && s == (string)"0000"){
return d[i][j][os] = 0;
}
sort(s.begin(),s.end());
for(int k = 3 ; k>=0 ; k--){
if(s[k] -'0'!= 0)
d[i][j][os] = min(d[i][j][os] , dp(pos - 1, s[k]-'0',s)+abs(j - (s[k]-'0')));
else if(pos - 1< n){
d[i][j][os] = min(d[i][j][os] , dp(pos - 1, start[pos],s) + abs(j - start[pos]));
break;
}
}
return d[i][j][os];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d %d",&start[i],&dest[i]);
}
cout<<dp(0,1,"0000") + 2 *n ;
return 0;
}