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;
}