题目大意
给你一个 (n(3leq nleq 50)) 个点的完全图,每条边都有边权,且边权为 ([1,10^4]) 范围内的随机数,要求删掉 (k(1leq kleq min(n-2,5))) 条边,使得 (1sim n) 的最短路最长,输出删去 (k) 条边后最长的最短路。
题解
发现题目强调了边权随机,容易想到最短路上边的数量应该很少,考虑暴力枚举删边。因此只需每次求一遍最短路,在最短路上选1条边删掉,再往下递归,再求一遍最短路,再选一条边删掉,直至选完 (k) 条边,去求得的 (1sim n) 所有最短路中的最大值即可。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
#define RG register int
#define LL long long
template<typename elemType>
inline void Read(elemType &T){
elemType X=0,w=0; char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
T=(w?-X:X);
}
int Dis[51],G[51][51];
bool Mark[51][51];
int T,N,K,Ans;
const int INF=0x7fffffff;
struct Node{int Value,ID;};
struct cmpA{bool operator()(Node A,Node B){return A.Value>B.Value;}};
priority_queue<Node,vector<Node>,cmpA> Q;
bool vis[51];
int Dijkstra(int st){
memset(Dis,0x3f,sizeof(Dis));
memset(vis,0,sizeof(vis));
Dis[st]=0;Q.push((Node){0,st});
while(!Q.empty()){
int u=Q.top().ID;Q.pop();
if(vis[u]) continue;
vis[u]=true;
for(RG v=1;v<=N;++v){
if(Mark[u][v]||vis[v]) continue;
if(Dis[v]>Dis[u]+G[u][v]){
Dis[v]=Dis[u]+G[u][v];
Q.push((Node){Dis[v],v});
}
}
}
return Dis[N];
}
struct edge{int u,v;};
edge E[6][100];
int Que[2000],head,tail;
inline void Get_Path(int &cnt,int num){
head=1;tail=0;
Que[++tail]=N;
while(tail>=head){
int u=Que[head];++head;
for(RG v=1;v<=N;++v){
if(v==u||Mark[v][u]) continue;
if(Dis[v]+G[v][u]==Dis[u]){
Que[++tail]=v;++cnt;
E[num][cnt].u=u;E[num][cnt].v=v;
}
}
}
return;
}
void DFS(int num){
Ans=max(Ans,Dijkstra(1));
if(num==K) return;
int cnt=0;Get_Path(cnt,num);
for(RG i=1;i<=cnt;++i){
int u=E[num][i].u,v=E[num][i].v;
Mark[u][v]=Mark[v][u]=true;
DFS(num+1);
Mark[u][v]=Mark[v][u]=false;
}
return;
}
int main(){
Read(T);
while(T--){
Read(N);Read(K);
for(RG i=1;i<=N*(N-1)/2;++i){
int u,v,w;
Read(u);Read(v);Read(w);
G[u][v]=G[v][u]=w;
}
Ans=Dijkstra(1);
DFS(0);
printf("%d
",Ans);
}
return 0;
}