題目大意:
給出一張無向圖,求刪除一條邊後,對於所有的點對(i,j)使得 c = Sum(d[i][j)]最大的值。
分析:
如果僅僅是枚舉刪除某一條邊,是非常差的做法,我們要得到以下幾點信息:
首先我們要明確,如果刪除這麼一條邊——不在任何一條最短路徑a->b上的邊,那麼顯然c的值不會受到任何的改變。因此我們需要嘗試枚舉刪除的邊,都應該在某條最短路上。
在求初始c的時候,我們進行n遍djikstra算法。求得以每個節點爲起點,到所有其他節點距離和地值。在這個過程中記錄每條邊地前驅,目的是在算法結束以後,能夠找到哪些邊是最短路上的邊記錄他們的編號,並且對於所有的這些邊,把當前節點納入囊中,意味着這條邊是哪些節點最短路徑上的值,從而讓這些特定節點重新調用一邊最短路算法計算。
#include <bits/stdc++.h>
#define CLR(arr) memset(arr,0,sizeof(arr))
#define FUL(arr) memset(arr,0x3f,sizeof(arr))
#define NEG(arr) memset(arr,-1,sizeof(arr))
const int inf = 0x3f3f3f3f;
using namespace std;
const int maxn = 120;
const int maxm = 1100;
typedef long long ll;
int n,m,L;
struct HeapNode{
int u,d;
bool operator < (const HeapNode& rhs) const {
return d > rhs.d;
}
};
struct Edge{
int u,v,dist;
bool flag;
};
struct Dijkstra{
int d[maxn];
int p[maxn];
bool done[maxn];
int ecnt;
int n;
vector<Edge> edge;
vector<int> G[maxn];
vector<int> tree[maxm*3];
void AddEdge(int u,int v,int d){
edge.push_back(Edge{u,v,d,1});
G[u].push_back(ecnt++);
edge.push_back(Edge{v,u,d,1});
G[v].push_back(ecnt++);
}
void init(int _n){
n = _n;
for (int i = 0 ; i < n ;++i){
G[i].clear();
tree[i].clear();
}
edge.clear();
ecnt = 0;
}
ll dijkstra(int s){
FUL(d);
CLR(done);
NEG(p);
priority_queue<HeapNode> Q;
d[s] = 0;
Q.push(HeapNode{s,0});
while(!Q.empty())
{
HeapNode x = Q.top(); Q.pop();
int u = x.u;
if(done[u]) continue;
done[u] = true;
for (int i = 0 ; i < G[u].size() ;++i)
{
Edge &e = edge[G[u][i]];
if(!e.flag) continue;
if(d[e.v] > d[u] + e.dist)
{
d[e.v] = d[u] + e.dist;
Q.push(HeapNode{e.v,d[e.v]});
p[e.v] = G[u][i];
}
}
}
ll ans = 0;
for (int i = 0 ; i < n ; ++i)
if(i != s)
ans += ( d[i] == inf ? L : d[i]);
return ans;
}
void deleteEdge(int idx){
edge[idx].flag = 0;
edge[idx^1].flag = 0;
}
void restoreEdge(int idx){
edge[idx].flag = 1;
edge[idx^1].flag = 1;
}
void GetTree(int s){
for (int i = 0 ; i < n ; ++i)
{
if(i == s || p[i] == -1) continue;
tree[p[i]].push_back(s);
}
}
};
ll D[maxn];
int main()
{
while(scanf("%d%d%d",&n,&m,&L)==3)
{
int a,b,c;
Dijkstra solver;
solver.init(n);
for (int i = 0 ; i < m ; ++i)
{
cin >> a >> b >> c;
if(a==b) continue;
a--;b--;
solver.AddEdge(a,b,c);
}
ll ans1 = 0 , ans2 = 0;
for (int i = 0 ; i < n ; ++i)
{
D[i] = solver.dijkstra(i);
ans1 += D[i];
solver.GetTree(i);
}
ll tmp = 0;
for (int i = 0 ; i < solver.edge.size() ; i++){
solver.deleteEdge(i);
if (i % 2 == 0) tmp = ans1;
for (int j = 0 ; j < solver.tree[i].size() ; ++j)
{
int k = solver.tree[i][j];
tmp -= D[k];
tmp += solver.dijkstra(k);
}
ans2 = max(ans2,tmp);
solver.restoreEdge(i);
}
cout << ans1 <<' ' << ans2 << endl;
}
return 0;
}