《路线》题解

路线题解

题目描述

​ 在一个 N×M 的区域中存在有 P 个景点( 0<P\le10 ),且每一小区域的海拔高度是高低不一的。假设相临两 1×1 区域的高度差为 x ,则从其中一个区域移到另一区域将耗费 x^2+1 分钟的时间。我们要求得到一条由区域 (1,1) 出发,经过所有景点的路线,并保证花费的时间最短。

思路分析

​ 题目意思并不难,要求是求遍历完所以景点的花费最小值,因为是多个景点,所以直接用 DFS,BFS 极其麻烦,所以第一步便是对每个景点跑一边 Dijkstra ,对两点之间进行建边,时间复杂度为 O(P~NM~logNM ), 然后就转换成了非常经典旅行商问题,这时候搜索的话时间复杂度会达到 O(P!) ,非常的卡。所以正解就是非常经典的状压dp,时间复杂度为 O(2^PP^2)

dp[i][S] 表示以 i 为终点,已访问结点集合为 S (用二进制表示, 1 表示已经访问过, 0 表示未访问)的最短路径

​ 转移方程: dp[i][S]=min(dp[i][S],dp[j][S~XOR~(1<<(j-1))]+dis[j][i])

​ 初始化: dp[i][1<<(i-1)]=dis[0][i]

​ 答案: min~(dp[i][(1<<p)-1])

这是很基础的状压dp,不会的快去补课(状压dp

代码实现

#include<bits/stdc++.h>
using namespace std;
const int N=105;
int n,m,p,a[N][N],dis[N][N],vis[N][N];
int dx[6]={-1,0,1,0},dy[6]={0,1,0,-1};
int d[15][15];
struct node{
    int dis,x,y;
    node(){}
    node(int Dis,int X,int Y){dis=Dis,x=X,y=Y;}
    bool operator >(const node a)const{return dis>a.dis;}
};
struct spot{
    int x,y;
}sp[15]; 
priority_queue<node,vector<node>,greater<node> >q;
void dijkstra(int sx,int sy){
    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++){
            dis[i][j]=INT_MAX;
            vis[i][j]=0;
        }
    }
    dis[sx][sy]=0;
    q.push(node(0,sx,sy));
    while(!q.empty()){
        node nw=q.top();
        q.pop();
        if(vis[nw.x][nw.y]) continue;
        vis[nw.x][nw.y]=1;
        for(int i=0;i<4;i++){
            int x=nw.x+dx[i],y=nw.y+dy[i];
            if(x<1||x>n||y<1||y>m) continue;
            int w=(a[nw.x][nw.y]-a[x][y])*(a[nw.x][nw.y]-a[x][y])+1;
            if(dis[x][y]>dis[nw.x][nw.y]+w){
                dis[x][y]=dis[nw.x][nw.y]+w;
                q.push(node(dis[x][y],x,y));
            }
        }
    }
}
int dp(){
    int dp[15][1<<11];
    memset(dp,0x3f,sizeof(dp));
    for(int i=1;i<=p;i++){
        dp[i][1<<(i-1)]=d[0][i];
    }
    for(int s=1;s<=(1<<p)-1;s++){
        for(int i=1;i<=p;i++){
            if(s&(1<<(i-1))){
                for(int j=1;j<=p;j++){
                    if((s&(1<<(j-1)))&&i!=j){
                    	
                        dp[i][s]=min(dp[i][s],dp[j][s^(1<<(i-1))]+d[i][j]);
                    }
                }
            }
        }
    }
    int ans=INT_MAX;
    for(int i=1;i<=p;i++){
        ans=min(ans,dp[i][(1<<(p))-1]);
    }
    return ans;
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
        }
    }
    cin>>p;
    for(int i=1;i<=p;i++){
        cin>>sp[i].x>>sp[i].y;
    }
    dijkstra(1,1);
    for(int i=1;i<=p;i++){
        d[0][i]=dis[sp[i].x][sp[i].y];
    }
    for(int i=1;i<=p;i++){
        dijkstra(sp[i].x,sp[i].y);
        for(int j=i+1;j<=p;j++){
            d[i][j]=d[j][i]=dis[sp[j].x][sp[j].y];
        }
    }
    cout<<dp();
    return 0;
}

彩蛋:

我永远喜欢珂朵莉!

3 个赞

大佬太强了

1 个赞

666