a tutorial on computer science

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  21 随笔 :: 0 文章 :: 17 评论 :: 0 Trackbacks
这个题的意思是说,一个人在一个奇怪的宾馆里,这个宾馆有N个电梯,这些电梯相邻两层的时间为T(i),而且这些电梯很奇怪,只在某些楼层会停(每个电梯停下的顶层和底层都不一样)。开始看的时候,把题意理解的巨复杂,觉得两个楼层之间的转移很难计算,后来才发现,换乘电梯需要的时间是固定的值(60s),汗。这样的话就是个最短路问题。不同电梯相同楼层之间的转移花费是60s,相同电梯不同楼层之间的转移花费是abs(i-j)*speed[n]。n是电梯号,i,j是楼层号。其实这个题可以用个无脑的BF算法搞一下,而且数据那么小。bf算法大概是这么个搞法:r[i][j][k][m]表示i个电梯到j层楼到j个电梯k层楼。转移方程自己搞。什么?复杂度太高了?额,500X500X500,搞不起。这个题边不太多,而且是单向边,那就搞个spfa优化下,应该OK。不过我看了一天的重点不是这个,这个题我刚开始理解成每个电梯之间的转移的代价不是固定的,然后就往分层图的方向想了下,发现没用。反正这种题的搞法就是最短路,如果能搞出个比较满意的状态出来,应该能OK。想了下发现可以搞个r[i][j]表示第一层楼到达j个电梯j层楼的代价。好了,这就是个迪杰斯特拉嘛。。而且还是个赤裸裸的迪杰斯特拉,而且500^2的裸复杂度都无压力。当时没想到这个是个迪杰斯特拉,看错题了以为每次转移的代价不同。然后就开始yy了。yy了很久之后。。发现每次从一个点开始扩展,可以扩展出这么些个状态:继续坐这个电梯,走个遍;换乘电梯。那么这些状态里面有一个最小的,不难证明这个最小的肯定就是状态r[i][j]的最优值了,因为如果他从别的地方走再回来,肯定会比这个值大的嘛。。好吧,这就是迪杰斯特拉了。我还暗暗惊叹,原来迪杰斯特拉还可以这么玩,转移的代价不确定,竟然也可以这么搞,当时就觉得刘汝佳出的题不错。后来才发现题目也很普通。最近状态很不好,想题目要很久,代码也越写越凌乱,索性正确率还不错,早晚会出大麻烦。可能也是个必经的阶段吧。加油,ws.
#include <iostream>
#include <sstream> 
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#define INF ((1<<29) - 100)

using namespace std;

int nmap[6][110]; //第i个电梯能否到j层

int speed[6]; //第i个电梯的速度

int ndist[6][110];

int nvis[6][110];

int evlen[6];

int N,T;


void findmin(int &minstx,int &minsty)
{
  int i,j;
  minstx = minsty = -1;
  for(i=0;i<N;i++)
   for(j=0;j<100;j++)
   {
     if(nmap[i][j] && !nvis[i][j] && (ndist[minstx][minsty] > ndist[i][j] || minstx == -1))
     {
       minstx = i,minsty = j;
     }
   }
}


int getlen(int j,int minsty,int m)
{
    return abs(m - minsty)*speed[j];
}

void digs()
{
  int i,j;
  memset(nvis,0,sizeof(nvis));
 
  for(i=0;i<N;i++)
  {
    for(j=0;j<100;j++)
     ndist[i][j] = INF;
  } 

  for(i=0;i<N;i++)
  if(nmap[i][0])
  {
    ndist[i][0] = 0;
  }

  int k;
  
      for(i=0;i<N*100;i++)
      {
        int minstx = -1,minsty = -1;
        findmin(minstx,minsty);
        if(minstx == -1)  return;
        nvis[minstx][minsty] = 1;
        //printf("nidst:: %d %d %d\n",minstx,minsty,ndist[minstx][minsty]);
        for(j=0;j<N;j++) //沿着电梯上一层,或者等到下一个电梯,进入。
        {
         if(j == minstx)
         {
           int m = minsty + 1;
           while(m != minsty)
           {
             if(nmap[j][m] && !nvis[j][m])
             {
                ndist[j][m] = min(ndist[j][m],ndist[j][minsty] + getlen(j,minsty,m));
             }
             m++,m%=100;
           }
           continue;
         } 
         //等到j个电梯,minsty  ,cost(ndist[minstx][minsty],minstx,j,minsty)   
         if(nmap[j][minsty] && !nvis[j][minsty])
         {
            ndist[j][minsty] = min(ndist[j][minsty],ndist[minstx][minsty] + 60); 
         } 
       }
      }
}

int main()
{
  int i,j; 
  string str;
  while(scanf("%d%d",&N,&T) != EOF)
  {
    memset(nmap,0,sizeof(nmap));
    for(i=0;i<N;i++)
      scanf("%d",&speed[i]);
    getline(cin,str);
    for(i=0;i<N;i++)
    {
      getline(cin,str);
      stringstream ss(str);
      int tmp,s=-1,e=-1;
      while(ss>>tmp)
      {
        if(s == -1) s = tmp;
        nmap[i][tmp] = 1;
        e = tmp;
      }
      evlen[i] = e - s;
    }
   digs();
   int ansx = -1;
   for(i=0;i<N;i++)
    if(nmap[i][T] && (ansx == -1 || ndist[ansx][T] > ndist[i][T]))
      ansx = i;
   if(ansx == -1 || ndist[ansx][T] == INF) printf("IMPOSSIBLE\n");
   else printf("%d\n",ndist[ansx][T]);
  }
  return 0;
}
 
posted on 2012-07-22 23:43 bigrabbit 阅读(1079) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理