题意
给N个点,M条边,如果两个点之间没有边,则默认为l。问所有点两两之间最短路之和是多少。然后删除一条边,问删除某一条边后最大是多少。
题解
这道题第一问可以很简单用Floyd算法求解。但是第二问如果使用Floyd算法,就会存在超时的问题。贪心上也没有比较好的策略,因此考虑使用最短路算法暴力枚举。但是由于暴力枚举可能超时,因此引入最短路树的概念。最短路树就是一个点到其他所有点的最短路所形成的树。 在使用最短路算法松弛的时候记录一下前置节点,就可以轻而易举的得到最短路树。然后对于暴力求解的过程,如果我们删除的边不在最短路上,那么最短路将不会重新计算。这样整体的复杂度就会变成O(N^2*M*log(N)),这个时间复杂度刚好足够。
注意事项
需要注意的是,这道题存在重边的情况,对于重边,如果删除一条边,则会采用其他边顶替。这一点在处理的时候需要特别注意。
代码
#include <bits/stdc++.h>
#define LL long long
#define UP(i,l,h) for(int i=l;i<h;i++)
#define DOWN(i,h,l) for(int i=h-1;i>=l;i--)
#define W(t) while(t)
#define MEM(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MAXN 210
#define COUT(x) cout<<x<<endl
#define int LL
using namespace std;
int dis[MAXN][MAXN];
int n,m,l;
struct Node {
int u,d;
bool operator < (
const Node v)
const {
return d>v.d;
}
Node(
int u,
int d):u(u),d(d) {}
};
bool vis[MAXN];
int d[MAXN],p[MAXN];
int dijkstra(
int u) {
MEM(vis,
0);
UP(i,
0,n) d[i]=l;
MEM(p,-
1);
priority_queue<Node> q;
q.push(Node(u,
0));
d[u]=
0;
W(!q.empty()) {
int x=q.top().u;
q.pop();
if(vis[x])
continue;
vis[x]=
true;
UP(i,
0,n) {
if(d[x]+dis[x][i]<d[i]) {
d[i]=d[x]+dis[x][i];
p[i]=x;
q.push(Node(i,d[i]));
}
}
}
int sum=
0;
UP(i,
0,n) {
sum+=d[i];
}
return sum;
}
int ans[MAXN];
bool tree[MAXN][MAXN];
bool inTree[MAXN][
4050];
struct Edge {
int u,v,w;
Edge(
int u,
int v,
int w):u(u),v(v),w(w) {}
};
vector<Edge> edges;
int sec[MAXN][MAXN];
main() {
W(~
scanf(
"%lld%lld%lld",&n,&m,&l)) {
edges.clear();
int a,b,s;
UP(i,
0,n) {
UP(j,
0,n) {
dis[i][j]=sec[i][j]=(i==j?
0:l);
}
}
UP(i,
0,m) {
scanf(
"%lld%lld%lld",&a,&b,&s);
if(dis[a-
1][b-
1]>=s) {
sec[a-
1][b-
1]=sec[b-
1][a-
1]=min(sec[b-
1][a-
1],dis[b-
1][a-
1]);
dis[a-
1][b-
1]=dis[b-
1][a-
1]=s;
}
else{
sec[a-
1][b-
1]=sec[b-
1][a-
1]=min(sec[b-
1][a-
1],s);
}
edges.push_back(Edge(a-
1,b-
1,s));
}
MEM(inTree,
false);
UP(i,
0,n) {
ans[i]=dijkstra(i);
MEM(tree,
false);
UP(j,
0,n) {
if(p[j]!=-
1)
tree[p[j]][j]=tree[j][p[j]]=
true;
}
UP(j,
0,m) {
if(tree[edges[j].u][edges[j].v]) {
inTree[i][j]=
true;
}
}
}
int temp1=
0;
UP(i,
0,n) temp1+=ans[i];
int temp2=temp1;
UP(i,
0,m) {
if(dis[edges[i].u][edges[i].v]!=edges[i].w)
continue;
int temp3=
0;
int distemp=dis[edges[i].u][edges[i].v]=dis[edges[i].v][edges[i].u];
dis[edges[i].u][edges[i].v]=dis[edges[i].v][edges[i].u]=sec[edges[i].v][edges[i].u];
UP(j,
0,n) {
if(inTree[j][i]) temp3+=dijkstra(j);
else temp3+=ans[j];
}
dis[edges[i].u][edges[i].v]=dis[edges[i].v][edges[i].u]=distemp;
temp2=max(temp2,temp3);
}
printf(
"%lld %lld\n",temp1,temp2);
}
}