codeforces 983C(dp or shortest path)

一般而言规划题目侧重于思路,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<

cnt值为715,总共的状态715*10 * 2000为 1400万左右,单实际用到的状态很少,不是所有状态都可达到,实际使用状态在百万左右,这样乘上状态转移代价为5实际为百万级算法代价,加上使用map大概千万级的计算量


参考别人的算法,也有使用只记录前三个上电梯的人,因为第四个人只要上了,电梯我们只能选择去送其中一个人。这样电梯内总不会多于3个人。

对于自己的代码,使用map,要十分注意的是,对任意一个状态,开始要先上下乘客(因为这样做总是合算的),对原来的s要先保存下来,因为这个WRONG了两次

#include
#include
#include
#include
#include
#include
using namespace std;

const int inf = 21474836;
const int maxn =2005;
const int F = 10;
mapd[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<

 


你可能感兴趣的:(动态规划,图论)