整理的算法模板:ACM算法模板總結(分類詳細版)
農夫約翰要把他的牛奶運輸到各個銷售點。
運輸過程中,可以先把牛奶運輸到一些銷售點,再由這些銷售點分別運輸到其他銷售點。
運輸的總距離越小,運輸的成本也就越低。
低成本的運輸是農夫約翰所希望的。
不過,他並不想讓他的競爭對手知道他具體的運輸方案,所以他希望採用費用第二小的運輸方案而不是最小的。
現在請你幫忙找到該運輸方案。
注意::
- 如果兩個方案至少有一條邊不同,則我們認爲是不同方案;
- 費用第二小的方案在數值上一定要嚴格小於費用最小的方案;
- 答案保證一定有解;
輸入格式
第一行是兩個整數 N,MN,M,表示銷售點數和交通線路數;
接下來 MM 行每行 33 個整數 x,y,zx,y,z,表示銷售點 xx 和銷售點 yy 之間存在線路,長度爲 zz。
輸出格式
輸出費用第二小的運輸方案的運輸總距離。
數據範圍
1≤N≤5001≤N≤500,
1≤M≤1041≤M≤104,
1≤z≤1091≤z≤109,
數據中可能包含重邊。
輸入樣例:
4 4
1 2 100
2 4 200
2 3 250
3 4 100
輸出樣例:
450
定義: 給一個帶權的圖,把圖的所有生成樹按權值從小到大排序,第二小的稱爲次小生成樹。
- 方法1: 先求最小生成樹,再枚舉刪去最小生成樹中的邊求解。時間複雜度。O(mlogm + nm)
- 方法2: 先求最小生成樹,然後依次枚舉非樹邊,然後將該邊加入樹中,同時從樹中去掉一條邊, 使得最終的圖仍是一棵樹。則一定可以求出次小生成樹。
設T爲圖G的一棵生成樹,對於非樹邊a和樹邊b,插入邊a,並刪除邊b的操作記爲(+a, -b)。
如果T+a-b之後,仍然是一棵生成樹, 稱(+a,-b)是T的一 個可行交換。
稱由T進行一次可行變換所得到的新的生成樹集合稱爲T的鄰集。
定理:次小生成樹一定在最小生成樹的鄰集中。
具體做法:
(這裏需要注意的是,由於樹外邊有可能等於兩個點之邊的最大值,這個時候不但要求出來兩點之間最大權邊,還要求出次大權邊)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=510,M=(1e4+7)*2;
int dis1[N][N],dis2[N][N],n,m,idx;
int h[M],e[M],ne[M],w[M],p[N];
struct node
{
int a,b,c;
bool flag;
}egdes[M/2];
bool cmp(node a,node b)
{
return a.c<b.c;
}
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int find(int x)
{
if(x!=p[x]) p[x]=find(p[x]);
return p[x];
}
void dfs(int u,int fa,int max_1d,int max_2d,int d1[],int d2[])
{
d1[u]=max_1d,d2[u]=max_2d;
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(j==fa) continue;
int maxt1=max_1d,maxt2=max_2d;
if(w[i]>maxt1) maxt2=maxt1,maxt1=w[i];
else if(w[i]<maxt1&&w[i]>maxt2) maxt2=w[i];
dfs(j,u,maxt1,maxt2,d1,d2);
}
}
int main()
{
memset(h,-1,sizeof h);
cin >>n>>m;
for(int i=0;i<=n;i++) p[i]=i;
for(int i=0;i<m;i++)
{
int a,b,c;
cin >>a>>b>>c;
egdes[i]={a,b,c};
}
sort(egdes,egdes+m,cmp);
ll sum=0;
for(int i=0;i<m;i++)
{
int a=find(egdes[i].a),b=find(egdes[i].b),c=egdes[i].c;
if(a!=b)
{
p[a]=b;
sum+=c;
add(egdes[i].a,egdes[i].b,c),add(egdes[i].b,egdes[i].a,c);
egdes[i].flag=true;
}
}
for(int i=1;i<=n;i++) dfs(i,-1,-1,-1,dis1[i],dis2[i]);
ll ans=1e18;
for(int i=0;i<m;i++)
{
if(!egdes[i].flag)
{
int a=egdes[i].a,b=egdes[i].b,c=egdes[i].c;
if(c>dis1[a][b]) ans=min(ans,sum+c-dis1[a][b]);
else if(c>dis2[a][b]) ans=min(ans,sum+c-dis2[a][b]);
}
}
cout <<ans<<endl;
}