秦始皇的国家公路系统
问题:
1. prim如何重构出树,记录一个from数组就可以了,具体看代码
2. 求次小生成树的时候,dfs求到某个点的最长边
3. 次小生成树和最小生成树至多有一条边不一样
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1010;
struct Node{
int x, y, cnt;
}nodes[N];
double dist[N], g[N][N], d[N][N];
int from[N];
int st[N], n;
int gst[N][N];
int h[N], ne[2*N], e[2*N], idx;
double w[2*N];
void add(int a, int b, double c){
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
double prim(){
for(int i = 1; i <= n; i++) dist[i] = g[i][i] = 2e9;
memset(st, 0, sizeof st);
dist[1] = 0;
double res = 0;
idx = 0;
for(int i = 1; i <= n; i ++) h[i] = -1;
for(int i = 1; i <= n; i ++){
int t = -1;
for(int j = 1; j <= n; j ++){
if(!st[j] && (t == -1 || dist[t] > dist[j])) t = j;
}
st[t] = 1;
if(dist[t] == 0x3f3f3f3f) return -1;
res += dist[t];
if(t != 1) add(t, from[t], g[t][from[t]]), add(from[t], t, g[t][from[t]]);
for(int j = 1; j <= n; j++){
if(dist[j] > g[t][j]) from[j] = t, dist[j] = g[t][j];
}
}
return res;
}
void dfs(int u, int fa, double d[]){
for(int i = h[u]; i != -1; i = ne[i]){
int j = e[i];
if(j == fa) continue;
d[j] = max(max(d[u], d[j]), w[i]);
dfs(j, u, d);
}
}
int main(){
int T; cin >> T;
while(T--){
scanf("%d", &n);
for(int i = 1; i <= n; i++){
int x, y, p; scanf("%d %d %d", &x, &y, &p);
nodes[i] = {x, y, p};
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j ++){
int dx = nodes[i].x - nodes[j].x; int dy = nodes[i].y - nodes[j].y;
g[i][j] = sqrt(dx * dx + dy * dy);
gst[i][j] = 0;
}
}
double sum = prim();
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++) d[i][j] = 0;
dfs(i, -1, d[i]);
}
double res = 0;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j ++){
if(i == j) continue;
if(gst[i][j]) res = max(res, (nodes[i].cnt + nodes[j].cnt) / (sum - g[i][j]));
else res = max(res, (nodes[i].cnt + nodes[j].cnt) / (sum - d[i][j] ) );
}
}
printf("%.2lf\n", res);
}
return 0;
}
还有第二条路吗
带重边的次小生成树
看了下别人的代码,发现直接把所有的边存下来就可以了,最后的时候再比较没有使用过的边就行
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 110;
int dist[N], g1[N][N], st[N], n;
int from[N];
int h[N], ne[2*N], e[2*N], w[2*N], idx;
int gst[N][N];
int g2[N][N];
int d[N][N];
void add(int a, int b, int c){
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int prim(){
for(int i = 1; i <= n; i ++) dist[i] = 2e9;
memset(st, 0, sizeof st);
idx = 0;
for(int i = 1; i <= n; i ++) h[i] = -1;
dist[1] = 0;
int res = 0;
for(int i = 1; i <= n; i ++){
int t = -1;
for(int j = 1; j <= n; j ++){
if(!st[j] && (t == -1 || dist[t] > dist[j])) t = j;
}
st[t] = 1;
if(dist[t] == 2e9) return -1;
if(t != 1) add(t, from[t], g1[t][from[t]]), add(from[t], t, g1[t][from[t]]), gst[t][from[t]] = gst[from[t]][t] = 1;
res += dist[t];
for(int j = 1; j <= n; j++){
if(dist[j] > g1[t][j]){
from[j] = t;
dist[j] = g1[t][j];
}
}
}
return res;
}
void dfs(int u, int fa, int d[]){
for(int i = h[u]; i!=-1; i=ne[i]){
int j = e[i];
if(j == fa) continue;
d[j] = max({d[j], d[u], w[i]});
dfs(j, u, d);
}
return ;
}
int main(){
int T; cin >> T;
for(int C = 1; C <= T; C ++){
int m; scanf("%d %d", &n, &m);
// if(C == 28) cout << n << ' ' << m << endl;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j ++) g1[i][j] = g2[i][j] = 2e9, gst[i][j] = 0;
}
for(int i = 1; i <= m; i ++){
int a, b, c; scanf("%d %d %d", &a, &b, &c);
// if(C == 28) cout << a << ' ' << b << ' ' << c << endl;
if(c < g1[a][b]) g2[a][b] = g2[b][a] = g1[a][b], g1[a][b] = g1[b][a] = c;
else if(c < g2[a][b]) g2[a][b] = g2[b][a] = c;
}
int t = prim();
if(t == -1){
printf("Case #%d : No way\n", C);
}
else if(m == n - 1) printf("Case #%d : No second way\n", C);
else{
int sum2 = 2e9;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j ++) d[i][j] = 0;
dfs(i, -1, d[i]);
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j ++){
if(!gst[i][j]) g2[i][j] = g1[i][j];
}
}
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= n; j ++){
if(i == j) continue;
if(g2[i][j] != 2e9) sum2 = min(sum2, t - d[i][j] + g2[i][j]);
}
}
printf("Case #%d : %d\n", C, sum2);
}
}
return 0;
}
最小树形图-朱刘算法-指挥网络