AtCoder Beginner 073 joisino's travel(多源最短路徑Floyd|DFS)

題目鏈接

題意

一共有n個點,m個邊,現在一個人要去其中的r個地點R1,R2,R3,R4…Rr(不一定按照這個順序)他可以坐飛機去第一個點,然後坐飛機從最後一個點返回,剩下的點只能走路,讓我們求出“經過這r個點的最短路程”


這個題我坑了,剛開始沒有想到可以從任意一個點出發。一直以爲題意是必須從第一個點出發,所以把dfs()裏面的for(int i=1;i<=r;i++)寫成了for(int i=2;i<=r;i++),後來想到可以從任意一個路徑出發的時候,這裏忘了改過去了
/(ㄒoㄒ)/~~自作聰明圖省事啊…


解決

  1. 跑一遍floyd,求出多源最短路徑
  2. 枚舉起點,深搜即可(由於r<=8,所以深搜的深度並不會很深)
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<(b);++i)
const int INF = 0x3f3f3f3f;

bool vis[10];
int ans=INF;
int n,m,r;
int R[10];
int d[205][205];
void dfs(int x,int cur)         //x是地點編號,cur是已經走過的距離
{
    bool flag = 1;
    for(int i=1;i<=r;i++) if(!vis[R[i]]) flag=0 ;
    if(flag&&cur<ans){              //已經經過了所有的r個點
        ans=cur;
        return;
    }

    for(int i=1;i<=r;i++){
        if(vis[R[i]]) continue;
        if(d[x][R[i]]>=INF) continue;
        vis[R[i]]=true;
        dfs(R[i],cur+d[x][R[i]]);
        vis[R[i]]=false;
    }
    return ;
}

int main()
{
    scanf("%d%d%d",&n,&m,&r);
    rep(i,1,r+1) scanf("%d",&R[i]);

    for(int i=0;i<205;i++) for(int j=0;j<205;j++) {
        if(i==j) d[i][j]=0;
        else d[i][j]=INF;
    }

    rep(i,0,m){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        d[u][v]=w;              //bidirectional雙向邊
        d[v][u]=w;
    }

    for(int k=1;k<=n;k++)       //floyd
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                d[i][j] = min(d[i][j],d[i][k]+d[k][j]);

    memset(vis,0,sizeof(vis));
    for(int i=1;i<=r;i++){      //枚舉起點
        vis[R[i]]=true;
        dfs(R[i],0);
        vis[R[i]]=false;
    }
    printf("%d\n",ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章