HDU 4856 (状态压缩DP+TSP)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4856

题目大意:有一个迷宫。迷宫里有些隧道,每个隧道有起点和终点,在隧道里不耗时。出隧道就耗时,你的任务是访问完所有隧道且仅一次,求最短耗时。

解题思路

暑假练习的时候。把英文读了N遍也没理解题意。

其实就是个最后不回到开头的TSP。

首先求BFS求两两隧道之间的最短路,注意BFS的起点是隧道i的终点,BFS的终点是隧道j的起点。

一定要特判一下两个隧道终点和起点是否一样,如果一样话dis=0, 我因为BFS没注意这个WA了10几次。

PS. 根据esxgx大神的说法,所有最短路算法(Dijkstra or Bellman-Ford)在每两个点距离为1的时候都会退化成普通的BFS,于是你在这里相当于手艹了个最短路。

 

然后就是对所有隧道进行TSP。

dp[i][j]表示状态i时,在j点的最少耗时,然后就是赤裸裸的TSP了。TSP的写法不唯一,我从别人那扒的这种TSP稍微快点。

 

#include "cstdio"
#include "string"
#include "iostream"
#include "cstring"
#include "queue"
#include "vector"
using namespace std;
int n,m,vis[20][20],dis[20][20],dir[4][2]={-1,0,1,0,0,-1,0,1},ans,dp[1<<15][20];
char map[20][20];
const int inf=0x3f3f3f3f;
struct status
{
    int x,y,dep;
    status(int x,int y,int dep):x(x),y(y),dep(dep) {}
};
struct tunnel
{
    int sx,sy,ex,ey;
}T[25];
int bfs(status a,status b)
{
    if(a.x==b.x&&a.y==b.y) return 0; //关键一步,如果两个隧道恰好拼在一起,则dis=0
    memset(vis,0,sizeof(vis));
    int ans=inf;
    queue<status> Q;
    Q.push(a);
    vis[a.x][a.y]=true;
    while(!Q.empty())
    {
        status t=Q.front();Q.pop();
        for(int s=0;s<4;s++)
        {
            int X=t.x+dir[s][0],Y=t.y+dir[s][1];
            if(X<1||X>n||Y<1||Y>n||vis[X][Y]||map[X][Y]!='.') continue;
            vis[X][Y]=true;
            if(X==b.x&&Y==b.y) {ans=min(ans,t.dep+1);return ans;}
            Q.push(status(X,Y,t.dep+1));
        }
    }
    return ans;
}
int main()
{
    ios::sync_with_stdio(false);
    string tt;
    while(cin>>n>>m)
    {
        memset(dis,0,sizeof(dis));
        for(int i=1;i<=n;i++)
        {
            cin>>tt;
            for(int j=0;j<tt.size();j++) map[i][j+1]=tt[j];
        }
        for(int i=1;i<=m;i++)
            cin>>T[i].sx>>T[i].sy>>T[i].ex>>T[i].ey;
        for(int i=1;i<=m;i++)
            for(int j=1;j<=m;j++)
        {
            if(i==j) {dis[i][j]=0;}
            else dis[i][j]=bfs(status(T[i].ex,T[i].ey,0),status(T[j].sx,T[j].sy,0));
        }
        int cnt=1<<m,res=inf;
        for(int i=0;i<cnt;i++)
        {
            for(int j=1;j<=m;j++)
            {
                int s=(1<<(j-1));
                if((i&s)==0) continue;
                if(i==s) dp[i][j]=0;
                else dp[i][j]=inf;
                for(int k=1;k<=m;k++)
                {
                    int t=(1<<(k-1));
                    if((i&t)==0||k==j||dis[k][j]==inf) continue;
                    dp[i][j]=min(dp[i][j],dp[i^s][k]+dis[k][j]);
                }
                if(i==cnt-1) res=min(res,dp[i][j]);
            }
        }
        if(res==inf) printf("-1
");
        else printf("%d
",res);

    }
}
11887989 2014-10-16 20:17:15 Accepted 4856 171MS 2852K 2290 B C++ Physcal

 

 

 

原文地址:https://www.cnblogs.com/neopenx/p/4029624.html