要删除一条边之后使得c最大。
首先我们要知道,当求出最短路树后,删除不在树上的边最短路是不会变化的。因为n个点的最短路树有n - 1条边,所以对每一个节点枚举要删除的边的复杂度可以由O(m)降为O(n)。
如果用floyd,求得每对顶点间的最短路复杂度是O(n^3),然后对每一个点删边,总复杂度是O(n^5)。这样果断是不行的,然后就想到dijkstra。
用dijkstra求单源最短路的复杂度是O(mlogn),所以总的复杂度是O(n^2*m*logn),比floyd要好。
注意重边的处理,最好用邻接表存。
#include <iostream>
#include<vector>
#include<stdio.h>
#include<cstring>
#include<queue>
#define maxn 110
using namespace std;
int n,m,l;
struct Edge
{
int from,to,dist,v,exi,cost;
//v:是否是最短路树边
//exi:当前是否删除这条边
//cost:删除这条边的代价
};
struct HeapNode
{
int d,u;
bool operator < (const HeapNode& rhs) const
{
return d > rhs.d;
}
};
vector<Edge>edges;
vector<int>G[maxn];
int vis[maxn];
int d[maxn];
int p[maxn];
int ans1,ans2,c1,c2;
void init()
{
for(int i = 1; i <= n; i++) G[i].clear();
edges.clear();
ans1 = 0;
ans2 = 0;
}
void add_edge(int from,int to,int dist)
{
edges.push_back((Edge)
{
from,to,dist
});
int mm = edges.size();
G[from].push_back(mm - 1);
}
void dijkstra(int s)
{
priority_queue<HeapNode>Q;
for(int i = 1; i <= n; i++) d[i] = l;
d[s] = 0;
memset(vis,0,sizeof vis);
memset(p,-1,sizeof p);
Q.push((HeapNode)
{
0,s
});
while(!Q.empty())
{
HeapNode x = Q.top();
Q.pop();
int u = x.u;
if(vis[u]) continue;
vis[u] = 1;
for(int i = 0; i < G[u].size(); i++)
{
Edge& e = edges[G[u][i]];
if(e.exi == 0) continue;
if(d[e.to] > d[e.from] + e.dist)
{
d[e.to] = d[e.from] + e.dist;
p[e.to] = G[u][i];
Q.push((HeapNode)
{
d[e.to],e.to
});
}
}
}
}
void mark(int s) //标记最短路树边
{
if(p[s] == -1) return;
Edge& e = edges[p[s]];
if(e.v == 0)
{
e.v = 1;
int tmp = p[s] - 1; //标记它的反响边
if(tmp >= 0)
{
Edge& e1 = edges[tmp];
if(e.from == e1.to && e.to == e1.from && e1.v == 0)
{
e1.v = 1;
}
}
tmp = p[s] + 1;
if(tmp < 2 * m)
{
Edge& e2 = edges[tmp];
if(e.from == e2.to && e.to == e2.from && e2.v == 0)
{
e2.v = 1;
}
}
}
s = e.from;
}
int calc() //计算最短路之和
{
int tmp = 0;
for(int i = 1; i <= n; i++)
{
tmp+=d[i];
}
return tmp;
}
void work(int s)
{
for(int i = 0; i < edges.size(); i++)
{
edges[i].v = 0;
edges[i].exi = 1;
}
dijkstra(s);
c1 = calc();
ans1+=c1;
for(int i = 1; i <= n; i++)
mark(i);
for(int i = 0; i < edges.size(); i+=2) //因为每条边存了两遍(正反向),所以+2
{
Edge& e = edges[i];
Edge& e1 = edges[i + 1];
if(e.v)//如果是最短路树边
{
e.exi = 0;
e1.exi = 0;
dijkstra(s);
e.exi = 1; //记得一定要还原!!
e1.exi = 1;
int tmp = calc();
e.cost+=tmp;
e1.cost+=tmp;
}
else //不然最短路没有变化
{
e.cost+=c1;
e1.cost+=c1;
}
}
}
int main()
{
while(scanf("%d %d %d",&n,&m,&l)!=EOF)
{
init();
for(int i = 1; i <= m; i++)
{
int from,to,dist;
scanf("%d %d %d",&from,&to,&dist);
add_edge(from,to,dist);
add_edge(to,from,dist);
}
for(int i = 1; i <= n; i++)
{
work(i);
}
for(int i = 0; i < edges.size(); i++)
{
ans2 = max(ans2,edges[i].cost);
}
printf("%d %d\n",ans1,ans2);
}
return 0;
}