思想还是很重要的....
首先,次小生成树就是用一条边替换最小生成树中的另一条边. 代价就是两条边的权值差.
证明:
我们把"在树上连一条新的边形成一个环,再删掉那个环上一条不是新边的边"的操作叫做边的替换.
替换的代价就是新边权减掉删掉的那条边的边权.
首先,最小生成树通过若干次替换总能够变成次小生成树,这是显然的.
我们把第一次替换的代价记为v1.剩下的所有替换的代价和记为v2.
首先v1和v2均不小于0.否则,对当前的最小生成树应用这些替换,会使总的权值和减小,当前树就不是最小生成树了.
那么如果v2等于0,相当于我们只进行第一次替换,然后什么都不干,于是我们仅通过一次替换得到次小生成树.
如果v2大于0,那么它的权值一定大于只进行第一次替换的权值,此时新树的权值比原树大v1+v2.
而我们肯定有一颗树的权值比原树大v1.因此,我们得到:新树的权值比原树大,还比进行了一次替换的树大.
所以这棵树肯定不是次小生成树.
于是次小生成树一定是仅通过一次在最小生成树上的边替换得到的.
假设我们用边(i,j) 替换边 (a,b) ,边权函数为 e ,可知 e(i,j)-e(a,b) 应当最小.
我们枚举非树边 (i,j) ,然后计算树上i到j路径上的最长边.
对于常规生成树,显然可以倍增求 LCA(i,j) 以及求路径上的最值.
Kruskal的次小生成树不会TAT
对于Prim,需要开一个数组 f(i,j) 表示最小生成树上i到j的路径中的最长边长度.
维护的时候,如果我们新连了边 (i,j) ,其中 i 不在当前树中, j 在当前树中,那么有递推式
对于每一个当前树上的点k, f(i,k) = f(k,i) = max( f(k,j) , e(i,j) );
然后把 (i,j) 从边表中剔除(或者标记一下),之后我们枚举非树边的时候就方便一些......
为了取得j,还要记录每个节点连到当前树的最短边是哪一个节点的. 维护距离数组的时候顺带更新.
AC VIJOS 1070 最小生成树+次小生成树
ExPrim
#include <cstdio>
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <list>
typedef unsigned int uint;
typedef long long int ll;
typedef unsigned long long int ull;
typedef double db;
using namespace std;
inline int getint()
{
int res=0;
char c=getchar();
bool mi=false;
while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
return mi ? -res : res;
}
inline ll getll()
{
ll res=0;
char c=getchar();
bool mi=false;
while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
return mi ? -res : res;
}
//==============================================================================
//==============================================================================
//==============================================================================
//==============================================================================
const ll INF=((ll)1<<56)-1;
int n,m;
ll M[505][505];
ll S[505][505];
ll D[505];
int E[505];
ll F[505][505];
bool used[505];
void putres(ll x)
{ printf("Cost: %I64d
",x); }
int main()
{
n=getll();
m=getll();
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
M[i][j]=S[i][j]=INF;
for(int i=0;i<m;i++)
{
int a=getint()-1;
int b=getint()-1;
ll v=getint();
if(v<M[a][b])
{
S[a][b]=S[b][a]=M[a][b];
M[a][b]=M[b][a]=v;
}
else if(v<S[a][b])
S[a][b]=S[b][a]=v;
}
//Prim
for(int i=1;i<n;i++) D[i]=INF;
ll res=0;
int d;
for(d=0;d<n;d++)
{
int x=-1;
ll mi=INF;
for(int i=0;i<n;i++)
if(!used[i] && mi>D[i])
{ mi=D[i]; x=i; }
if(mi==INF) break; //unable to find any edge.
used[x]=true;
res+=mi;
F[E[x]][x]=F[x][E[x]]=mi;
for(int i=0;i<n;i++)
if(used[i] && i!=x && i!=E[x])
F[i][x]=F[x][i]=max(F[i][E[x]],mi);
M[E[x]][x]=M[x][E[x]]=S[x][E[x]];
for(int i=0;i<n;i++)
if(!used[i] && D[i]>M[i][x])
{ D[i]=M[i][x]; E[i]=x; }
}
if(d!=n) { putres(-1),putres(-1); return 0; }
bool tag=true;
for(int i=0;i<n && tag;i++)
for(int j=0;j<n && tag;j++)
if(M[i][j]!=INF) tag=false;
if(tag) { putres(res),putres(-1); return 0; }
ll delta=INF;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(M[i][j]!=INF)
delta=min(delta,M[i][j]-F[i][j]);
putres(res),putres(delta+res);
return 0;
}
ExKruskal
1 #include <cstdio>
2 #include <fstream>
3 #include <iostream>
4
5 #include <cstdlib>
6 #include <cstring>
7 #include <algorithm>
8 #include <cmath>
9
10 #include <queue>
11 #include <vector>
12 #include <map>
13 #include <set>
14 #include <stack>
15 #include <list>
16
17 typedef unsigned int uint;
18 typedef long long int ll;
19 typedef unsigned long long int ull;
20 typedef double db;
21
22 using namespace std;
23
24 inline int getint()
25 {
26 int res=0;
27 char c=getchar();
28 bool mi=false;
29 while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
30 while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
31 return mi ? -res : res;
32 }
33 inline ll getll()
34 {
35 ll res=0;
36 char c=getchar();
37 bool mi=false;
38 while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
39 while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
40 return mi ? -res : res;
41 }
42
43 //==============================================================================
44 //==============================================================================
45 //==============================================================================
46 //==============================================================================
47
48 const ll INF=(ll(1)<<56)-1;
49
50 int n,m;
51
52 struct vedge
53 {
54 int a,b;
55 ll v;
56 bool used;
57 }E[200000];
58 int p[200000];
59 bool cmp(int x,int y)
60 { return E[x].v<E[y].v; }
61
62 //union find
63 int ft[1000];
64 void INIT(int size)
65 { for(int i=0;i<=size;i++) ft[i]=i; }
66 int findf(int x)
67 { return ft[x]==x ? x : ft[x]=findf(ft[x]); }
68 void con(int a,int b)
69 { ft[findf(a)]=findf(b); }
70
71 struct edge
72 {
73 int in;
74 ll v;
75 edge*nxt;
76 }pool[10000];
77 edge*et=pool;
78 edge*eds[1000];
79 void addedge(int i,int j,ll v)
80 {
81 et->in=j; et->v=v; et->nxt=eds[i]; eds[i]=et++;
82 et->in=i; et->v=v; et->nxt=eds[j]; eds[j]=et++;
83 }
84 #define FOREACH_EDGE(i,j) for(edge*i=eds[j];i;i=i->nxt)
85
86 //DFS
87 int f[11][1050];
88 ll mx[11][1050];
89 int dep[1050];
90 ll v[1050];
91 int curd;
92 void DFS(int x,ll k)
93 {
94 dep[x]=curd;
95 v[x]=k;
96 mx[0][x]=max(v[x],v[f[0][x]]);
97
98 curd++;
99 FOREACH_EDGE(i,x)
100 if(i->in!=f[0][x])
101 {
102 f[0][i->in]=x;
103 DFS(i->in,i->v);
104 }
105 curd--;
106 }
107
108 void gen()
109 {
110 for(int d=1;d<11;d++)
111 {
112 for(int i=0;i<n;i++)
113 {
114 f[d][i]=f[d-1][f[d-1][i]];
115 mx[d][i]=max(mx[d-1][i],mx[d-1][f[d-1][i]]);
116 }
117 }
118 }
119
120 int getLCA(int a,int b)
121 {
122 if(dep[a]<dep[b]) swap(a,b);
123
124 for(int i=10;i>=0;i--)
125 if(dep[f[i][a]]>=dep[b]) a=f[i][a];
126
127 if(a==b) return b;
128
129 for(int i=10;i>=0;i--)
130 if(f[i][a]!=f[i][b])
131 a=f[i][a],b=f[i][b];
132
133 return f[0][a];
134 }
135
136 ll getv(int a,int b)
137 {
138 if(dep[a]<dep[b]) swap(a,b);
139
140 ll res=-INF;
141
142 int lca=getLCA(a,b);
143
144 if(lca==a) res=v[b];
145 else if(lca==b) res=v[a];
146 else res=max(v[a],v[b]);
147
148 for(int i=10;i>=0;i--)
149 if(dep[f[i][a]]>dep[lca])
150 res=max(res,mx[i][a]),a=f[i][a];
151
152 for(int i=10;i>=0;i--)
153 if(dep[f[i][b]]>dep[lca])
154 res=max(res,mx[i][b]),b=f[i][b];
155
156 return res;
157 }
158
159
160 int main()
161 {
162
163 freopen("in.txt","r",stdin);
164 freopen("out.txt","w",stdout);
165
166 n=getint();
167 m=getint();
168 for(int i=0;i<m;i++)
169 E[i].a=getint()-1,
170 E[i].b=getint()-1,
171 E[i].v=getll();
172
173 //Kruskal
174 for(int i=0;i<m;i++) p[i]=i;
175 stable_sort(p,p+m,cmp);
176 INIT(n+1);
177 ll cres=0;
178 int tot=0;
179 for(int i=0;i<m;i++)
180 if(findf(E[p[i]].a)!=findf(E[p[i]].b))
181 {
182 con(E[p[i]].a,E[p[i]].b);
183 addedge(E[p[i]].a,E[p[i]].b,E[p[i]].v);
184 E[p[i]].used=true;
185 cres+=E[p[i]].v;
186 tot++;
187 }
188
189 ll res=INF;
190 if(tot!=n-1) cres=-1;
191 else
192 {
193 //second generated tree
194 f[0][0]=0;
195 curd=0;
196 DFS(0,0);
197 gen();
198
199 for(int i=0;i<m;i++)
200 if(!E[i].used && E[i].a!=E[i].b)
201 {
202 ll rk=getv(E[i].a,E[i].b);
203 res=min(res,cres-rk+E[i].v);
204 }
205 }
206
207 if(res>=INF/10) res=-1;
208
209 printf("Cost: %I64d
Cost: %I64d
",cres,res);
210
211 return 0;
212 }
很久很久以前写的,但是一开始WA了.....错在哪呢.....
变量名打错,n打成m! 倍增的时候dep[lca]写成lca! shenmegui.........
最终A了.....不是很快的样子.....
..