题意:给出一张完全图,要求删掉k条边之后,最长的最短路。
题解:dijkstra
递归,每递归一次求一下最短路,并将该条最短路其中的一条删掉即可。
递归的时候注意些小问题,路径的话要么开二维数组记录path,要么新建一个。还有别用全局变量…wa了好久。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<fstream>
#include<set>
#include<map>
#include<sstream>
#include<iomanip>
#define ll long long
using namespace std;
const int inf = 0x3f3f3f3f;
const int manx = 55; //与n相对,对应顶点的个数
const int mamx = 300; //与m相对,对应边的个数
priority_queue< pair<int, int> >q;
bool vis[manx]; //这里的标记数组与spfa的vis数组含义不同,这里标记是否入过队列
int d[manx];
int n, m, s, e; //s作为起点,e作为终点
int g[55][55], path[55];
void dijkstra() {
for (int i = 1; i <= n; i++) //初始化vis d 数组
d[i] = inf, vis[i] = 0;
d[s] = 0; //s作为起点
q.push(make_pair(0, s));
while (q.size()) {
int x = q.top().second; //取出队头
q.pop();
if (vis[x]) continue; //如果点x访问过,跳过,访问下一个队头
vis[x] = 1; //访问x做标记
for (int v = 1; v <= n; v++) {
if (!g[x][v]) continue;
int w = g[x][v];
if (d[v] > d[x] + w) {
//松弛操作,更新距离
d[v] = d[x] + w;
path[v] = x;
q.push(make_pair(-d[v], v)); //把更新的距离和点入队,这里距离取负变成小根堆
}
}
}
}
int t, k, u, v, w, ans;
void dfs(int kk) {
//memset(path, 0, sizeof(path));
dijkstra();
if (kk == 0) {
ans = max(ans, d[n]);
return;
}
int j = n, p[55], num = 0;
p[++num] = n;
while (path[j]) {
p[++num] = path[j];
j = path[j];
}
for (int i = 1; i < num; i++) {
int ww = g[p[i]][p[i + 1]];
g[p[i]][p[i + 1]] = g[p[i + 1]][p[i]] = 0;
dfs(kk - 1);
g[p[i]][p[i + 1]] = g[p[i + 1]][p[i]] = ww;
}
}
int main() {
//freopen("1007.in", "r", stdin);
scanf("%d", &t);
while (t--) {
ans = 0;
scanf("%d%d", &n, &k);
for (int i = 1; i <= n * (n - 1) / 2; i++) {
scanf("%d%d%d", &u, &v, &w);
g[u][v] = g[v][u] = w;
}
s = 1;
dfs(k);
printf("%d\n", ans);
}
return 0;
}