整理的算法模板: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;
}