查看文章
 
PKU 2688[BFS+状态压缩dp/TSP]
2010-10-29 18:30

/*PKU 2688 BFS+状态压缩DP/TSP 
dp[i][j] 假设j中的二进制位为1的个数为k那些该方程表示,清除了k个dirt,并且根据位表示不同的dirt, 且当前结束时候机器人的位置在第i个dirt上面花费的最少步数,于是状态转移就不难理解了,WA两次,原来是我的INF申明的是int的最大数,再加一个int就成为负数,于是就WA了
*/
#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define F(i, s, e) for(int i(s), __(e); i<=__; i++)
#define FOR(i, s, e) for(int i(s), __(e); i<__; i++)
#define CLR(arr, v) memset(arr, v, sizeof(arr))
#define Debug(v) printf("%d\n", v);
#define INF 0x7fffffff
#define size 21
int  h, w;
int  direction[4][2]={
    {1, 0}, {-1, 0}, {0, 1}, {0, -1}
};
char map[size][size];
struct POINT
{
   int x, y, step;
   POINT( ){ }
   POINT(int xx, int yy, int s):x(xx),y(yy),step(s){ }
}point[size];
int  num;
bool visit[size][size];
int  dist[size][size], getId[size][size];
bool check(int y, int x)
{
    if (y>=1 && y<=h && x>=1 && x<=w && visit[y][x]==false&&map[y][x]!='x') return true;
    return false;   
}
void BFS(POINT st, int id)//计算st到其它点的最短距离
{
    POINT  cur, next;
    queue<POINT>Q;
    Q.push( POINT(st.x, st.y, 0) );
    CLR(visit, false);
    visit[st.y][st.x]=true;
    while ( !Q.empty( ) )
    {
         cur = Q.front( ); Q.pop( );
         FOR(i, 0, 4)
         {
             next.y = cur.y + direction[i][0];
             next.x = cur.x + direction[i][1];
             if (check(next.y, next.x) )
             {
                 visit[next.y][next.x]=true;
                 next.step = cur.step + 1;
                 Q.push( next );
                 if ( map[next.y][next.x]=='o' )//表示到达机器人的起点
                 {
                       dist[id][1] = dist[1][id]=next.step;
                 }else if( map[next.y][next.x]=='*') //表示脏的地方
                 {
                       int u = getId[next.y][next.x]; //取得当前点的ID
                       dist[u][id]=dist[id][u]=next.step;
                 }              
             }
         }
    }
}
int dp[11][1<<11];
void solve( )
{
    int ii;
    dp[1][0]=0; //1表示机器人的ID,0转化为二进制全部为0,表示清除了0个脏地方
    int Bound=(1<<(num-1))-1;
    F(i, 1, Bound) //表示状态
    {
       ii=i;
       F(j, 0, num-2) //j位
       {
           if ( (ii&(1<<j) )>=1 ) //判断ii的当前位是否为1
           {
               dp[j+2][i]=INF; //
               int s=(ii^(1<<j)); //上一个状态
               bool tag=false;
               F(k, 0, num-2)
               {
                   if ((s&(1<<k))>=1 )
                   {
                       dp[j+2][i]=min(dp[j+2][i], dp[k+2][s]+dist[j+2][k+2]);
                       tag=true;
                   }  
               }
               if (!tag) dp[j+2][i]=dist[j+2][1]; //表示的是清除第一个dirt
           }
       }   
    }
}
int  main( )
{
    freopen("in.txt","r",stdin);
    while (~scanf("%d%d", &w, &h) &&(w||h))
    {
       getchar( );
       num=1;
       F(i, 1, h){ F(j, 1, w)
       {
           scanf("%c", &map[i][j]);
           if (map[i][j]=='o') {point[1].y=i; point[1].x=j; }
           if (map[i][j]=='*')
           {
               point[++num].y=i;
               point[num].x=j;
               getId[i][j]=num;
           }
       } getchar( );
       }
       F( i, 1, num ) F(j, 1, num) dist[i][j]=INF;
       //下面BFS计算两两点之间的距离
       //Debug(point[1].y); Debug(point[1].x);
       BFS(point[1], 1);
       FOR(i, 2, num) BFS(point[i], i);
       bool mark=false;
       F( i, 2, num) if (dist[1][i]==INF) { mark=true; break; }
       if (mark) { puts("-1"); continue; }
       /*F(i, 1, num) {
           F(j, 1, num) printf("%d ", dist[i][j]);
           putchar('\n');
       }*/
       //两两点的距离计算完之后再用状态DP
       solve( );
       int ret=INF;
       if (num==1){ puts("0"); continue; }
       F(i, 2, num)
       {
           ret = min(ret, dp[i][(1<<(num-1))-1]);
       }
       if (ret<INF)
       printf("%d\n", ret);
       else puts("-1");
    }
    return 0;
}


类别:动态规划专栏||添加到搜藏 |分享到i贴吧|浏览(165)|评论 (0)
 
最近读者:
 
网友评论:
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
     

   
帮助中心 | 空间客服 | 投诉中心 | 空间协议
©2012 Baidu