給n個點,m條邊,如果兩個點之間沒有邊,則預設為l。問所有點兩兩之間最短路之和是多少。然後刪除一條邊,問刪除某一條邊後最大是多少。
這道題第一問可以很簡單用floyd演算法求解。但是第二問如果使用floyd演算法,就會存在超時的問題。貪心上也沒有比較好的策略,因此考慮使用最短路演算法暴力列舉。但是由於暴力列舉可能超時,因此引入最短路樹的概念。最短路樹就是乙個點到其他所有點的最短路所形成的樹。
在使用最短路演算法鬆弛的時候記錄一下前置節點,就可以輕而易舉的得到最短路樹。然後對於暴力求解的過程,如果我們刪除的邊不在最短路上,那麼最短路將不會重新計算。這樣整體的複雜度就會變成o(n^2*m*log(n)),這個時間複雜度剛好足夠。
需要注意的是,這道題存在重邊的情況,對於重邊,如果刪除一條邊,則會採用其他邊頂替。這一點在處理的時候需要特別注意。
#include
#define ll long long
#define up(i,l,h) for(int i=l;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<#define int ll
using
namespace
std;
int dis[maxn][maxn];
int n,m,l;
struct node
node(int u,int d):u(u),d(d) {}
};bool vis[maxn];
int d[maxn],p[maxn];
int dijkstra(int u)
return sum;
}int ans[maxn];
bool tree[maxn][maxn];
bool intree[maxn][4050];
struct edge
};vector
edges;
int sec[maxn][maxn];
main()
}up(i,0,m) else
edges.push_back(edge(a-1,b-1,s));
}mem(intree,false);
up(i,0,n)
up(j,0,m) }}
int temp1=0;
up(i,0,n) temp1+=ans[i];
int temp2=temp1;
up(i,0,m)
dis[edges[i].u][edges[i].v]=dis[edges[i].v][edges[i].u]=distemp;
// cout(te***);
temp2=max(temp2,te***);
}printf("%lld %lld\n",temp1,temp2);
}}
最短路樹 BZOJ 3694 最短路
題目傳送門 許可權題警告 顯然可以發現,將1到i路徑上的最後一條路切斷後,需要重新找到一條從i的子樹出發的最短路徑重新回到最短路樹上去.因此考慮一條邊什麼時候會被計算在答案中.設一條邊u v權值為val,只會可能對u,v到 lca u,v 之間的點產生影響.記錄源點1到節點i的距離為dep i 那麼...
最短路徑樹
問題描述 所謂最短路徑樹,就是從s出發,沿著樹上的邊走到任意點i,那麼經過的這些邊的權值和就是s到i的最短路徑。dijkstra演算法或spfa演算法不僅可計算從起點s到各點的最短路徑長度,同時也可得到以s為根的最短路徑樹。方法是在進行鬆弛操作時,如果d i c d j 時,除了更新d j 之外,還...
最短路徑,最短路徑樹和最小生成樹
首先介紹這三個概念,很多人都聽過最短路徑了,但是最短路徑樹卻很少聽過,關於最短路徑樹的介紹也不太多。而最短路徑樹和最小生成樹更是完全不同的兩個概念。最短路徑就是從乙個指定的頂點出發,計算從該頂點出發到其他所有頂點的最短路徑。通常用dijkstra演算法,floyd演算法求解。最短路徑樹spt sho...