Tokitsukaze and Rescue(DFS、最短路)

Tokitsukaze and Rescue

题目传送门

Tokitsukaze and Rescue

题意

一张完全图(双向边),删去k条边后,让新图的最短路的路径长度尽可能大

思路

先用dijkstra跑出最短路,删边肯定从这里面删的,然后枚举删除的边,再用递归求子问题(删k-1条边),ans存更新的答案
对于删边,可以采取开一个二维数组记录,也可以将删除的边记录为INF,记得回溯

代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
#define INF 0x3f3f3f3f
// #define TDS_ACM_LOCAL
const int N=59;
bool vis[N], lose[N][N];
int n, k, u, v, w, ans;
int mp[N][N], path[N], dis[N];

void dijkstra(){
    memset(path, 0, sizeof(path));          //存dijkstra的路径
    memset(dis, INF, sizeof(dis));          //存最短路的路径大小
    memset(vis, 0, sizeof(vis));
    dis[1]=0, path[1]=0;
    for(int i=1; i<n; i++){
        int d=INF, f=0;
        for(int i=1; i<=n; i++) if(!vis[i]&&dis[i]<d)   d=dis[i], f=i;
        vis[f]=1;
        for(int j=1; j<=n; j++){
            if(dis[f]+mp[f][j] < dis[j] && !lose[f][j]){
                dis[j]=dis[f]+mp[f][j];
                path[j]=f;
            }
        }
    }
}

void dfs(int x){
    dijkstra();
    if(x==k+1){                  //删k边,跑k+1次dijkstra
        ans=max(ans, dis[n]);    //dis[n]是最短路的长度,求最大值
        return ;
    }
    for(int i=n, pre=n; i; i=path[i]){
        lose[i][pre]=lose[pre][i]=1;    //枚举删除的边
        dfs(x+1);
        lose[i][pre]=lose[pre][i]=0;    //回溯
        pre=i;
    }
    return ;
}

void solve(){
    cin>>n>>k;
    memset(mp, INF, sizeof(mp));            //初始化图的距离
    memset(lose, 0, sizeof(lose));          //初始化删的边
    ans=0;
    for(int i=1; i<=n; i++) mp[i][i]=0;
    for(int i=1; i<=n*(n-1)/2; i++){
        cin>>u>>v>>w;
        mp[u][v]=mp[v][u]=w;
    }
    dfs(1);
    cout<<ans<<endl;
    return ;
}

int main(){
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
#ifdef TDS_ACM_LOCAL
    freopen("D:\\VS code\\.vscode\\testall\\in.txt", "r", stdin);
    freopen("D:\\VS code\\.vscode\\testall\\out.txt", "w", stdout);
#endif
    int T;
    cin>>T;
    while(T--)   solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xmyrzb/article/details/107704150