【3阶动规+状态压缩】s到达G

来源:互联网 发布:海泰克触摸屏编程手册 编辑:程序博客网 时间:2024/09/21 09:02



S对应point[0],G对应Point[n-1].中间点对应1~n-2

针对每个中间state有 

        len[state][s]+dist[s][t]  >=  len[state|(1<<(t-1))][t],state=1 to 1<<(n-2)-1

        其中len[state][s]<无穷(点s可以且已经被state最后访问),dist[s][t]<无穷(点s可以到达t),且state&(1<<(t-1))==0 (即点t尚未被状态state访问,从而state可达t)



#include <stdio.h>#include <assert.h>#include <string.h>#include <vector>#include <queue>#include <iostream>using namespace std;typedef pair<int,int> Pair;#define INF 0x7ffffff#define MAXSIZE 10000class Orienteering{  public:    void main();  private:    bool init(char buf[],int &w,int &h,vector<Pair> &points);    void bfs(char buf[],int w,int h,const vector<Pair> &points,vector<vector<int> > &dist);    int dp(const vector<vector<int> > &dist);}; /** * calculate min-cost of all (i,j), point i and j in points[] *  and store in dist[i][j] * params: @buf[]: the map *  @w: the width  @h: the height, 0<w,h<=100 *  @points[]: the point array, *  @dist[][]: elements init as INF * output: @dist[][] */void Orienteering::bfs(char buf[],int w,int h,const vector<Pair> &points,vector<vector<int> > &dist){  int n=points.size();  // record points' number on pNum[][]  int *pNum=new int[w*h];  memset(pNum,-1,w*h*sizeof(int));  for(int i=0;i<n;i++){    const Pair &p=points[i];    pNum[p.first*w+p.second]=i;  }  // minDst[i][j] is the min-distance between point (i,j)  int * minDst=new int[w*h];  // four directions  int drt[4][2]={{1,0},{-1,0},{0,1},{0,-1}};  // find nearest distances from point[i] to other points  for(int i=0;i<n;i++){    const Pair &p=points[i];    queue<Pair> que;    que.push(p);    int cnt=1;    memset(minDst,-1,w*h*sizeof(int));    minDst[p.first*w+p.second]=0;    while(!que.empty()){      Pair p=que.front(); que.pop();      int x0=p.first,y0=p.second;      // visit direction: left/right/up/down      for(int j=0;j<4;j++){        int x=x0+drt[j][0],y=y0+drt[j][1];        // ignore positions which is visited or can't be visited        if(x<0 || y<0 || x>=h || y>=w || buf[x*w+y]=='#'|| minDst[x*w+y]>=0)           continue;        minDst[x*w+y]=minDst[x0*w+y0]+1;        que.push(Pair(x,y));        int k=pNum[x*w+y];        if(k>=0){// if readched a point          dist[i][k]=minDst[x*w+y];          // if(k<i) assert(dist[k][i]==dist[i][k]);          cnt++;          if(cnt==n) break;        }      }    }  }  delete[] minDst;  delete[] pNum;}/** * find the min-cost from point 0 to point n-1 with all other points visited * params: @dist[i][j]: min-distance from point i to j * return: the min-distance from point 0 to n-1 with all check-points passed *    INF if not reachable or input don't satisfy specifications */int Orienteering::dp(const vector<vector<int> > &dist){  int n=dist.size();  int lp=0,rp=n-1;  if(n<2||n>sizeof(int)*8) return INF;  int size=1<<(n-2), lst=size-1;// lst is the state that all check-points(1~n-2) has been visited  // len[i][s] stands for current visit state is i(compressed binary number for check-points 1~n-2), with point s last visited   vector<vector<int> > len(size,vector<int>(n-1,INF));  vector<vector<int> > path(size,vector<int>(n-1,INF));    len[0][lp]=0;// init: in state 0, with point 0(start-point 'S') last visited  for(int i=0;i<=lst;i++){    for(int s=lp;s<rp;s++){      if(len[i][s]<INF){        for(int t=lp+1,mask=1;t<rp;t++,mask<<=1){          if(!(i&mask) && dist[s][t]<INF){// try to go from <state i,point s> to <state i|mask,point t>            int tmp=len[i|mask][t];            len[i|mask][t]=min(len[i|mask][t],len[i][s]+dist[s][t]);            if(len[i|mask][t] < tmp)              path[i|mask][t]=s;// record the path           }        }      }    }  }  // go to end-point rp from <state lst, point s>  int minLen=INF;  int l=INF;  for(int s=lp;s<rp;s++)    if(len[lst][s]<INF && dist[s][rp]<INF){      int tmp=minLen;      minLen=std::min(minLen,len[lst][s]+dist[s][rp]);      if(minLen<tmp){        l=s;      }    }  // print min-path  int state=lst,point=l;  cout<<"print path:"<<endl;  cout<<rp<<" <- ";  while(point<INF){    cout<<point;    if(point==0) break;    cout<<" <- ";    int tmp=path[state][point];    state-=(1<<(point-1));    point=tmp;  }  cout<<endl;  return minLen; }/** * init the points and buffer * record map in buf[], check points and S/G in points[] * @points[]: points[0] as point 'S', 1~n-2 as check-points, n-1 as 'G' * @return: true if parameters satisfy conditions */bool Orienteering::init(char buf[],int &w,int &h,vector<Pair> &points){  scanf("%d %d\n",&w,&h);  // if w or h don't satisfy conditions  if( w<1 || h<1 || w*h>MAXSIZE ) return false;  Pair tmp(-1,-1),start=tmp,end=tmp;  points.clear();  points.push_back(start);  for(int i=0;i<h;i++){    scanf("%s\n",buf+i*w);     for(int j=0;j<w;j++){      char c=buf[i*w+j];      if(c=='@') points.push_back(Pair(i,j));      else if(c=='S') {        if(start!=tmp) return -1; // S duplicated        start=Pair(i,j);      }      else if(c=='G') {        if(end!=tmp) return -1; // G duplicated        end=Pair(i,j);      }    }  }  // if no 'S' or 'G' found  if(start==tmp||end==tmp) return false;  points[0]=start;  points.push_back(end);  if(points.size()>20) return false;  return true;}/** * */void Orienteering::main(){  // record points that must be passed  int w,h;  char buf[10010];   vector<Pair> points;  if(!Orienteering::init(buf,w,h,points)) {    printf("-1\n");    return;  };  // find the nearest distance  between points in points[]  int n=points.size();   vector<vector<int> > dist(n,vector<int>(n,INF));  Orienteering::bfs(buf,w,h,points,dist);  // find the nearest path from start-point to end-point passing all points  int dst=Orienteering::dp(dist);  if(dst==INF) printf("-1\n");  else printf("%d\n",dst);}int main(int argc,char *argv[]){  Orienteering o;  o.main();  return 0;}


0 0
原创粉丝点击