题目大意:有N个点,M条路,现在给出K条路,这K条路是在M条路中将权值扩大的路。每给出一条,就要求求出最小生成树的权值
现在问每条路的最小生成树的权值和/K的最小值是多少
解题思路:先得到最小生成树,然后判断路是不是最小生成树的树边,如果不是,就不影响了
如果是的话,就要判断一下是不是要去掉该边,再添加新的边。
如果去掉该边的话,就相当于把最小生成树划分成了两个块,所以现在需要的是一条最小边来连接两个块
我们设dp[u][v]为u到 v和到以v为根的树的所有点的最小权值(以v为根就相当于有一条树边的一个结点是v的边断了,然后分成了两个块,而u和v在不同的块),这个可以通过dfs得到
得到这个了,那就可以得到每条树边断后,需要添加的最小权值边了,也是通过dfs得到
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
#define N 3010
#define ll long long
const int INF = 1000000000;
int n, m, tot;
int dis[N][N], best[N][N], d[N], f[N], dp[N][N];
bool vis[N];
vector<int> G[N];
void init() {
memset(dis, 0x3f, sizeof(dis));
int u, v, c;
for (int i = 0; i < m; i++) {
scanf("%d%d%d", &u, &v, &c);
dis[u][v] = dis[v][u] = c;
}
}
ll prim() {
memset(vis, 0, sizeof(vis));
ll ans = 0;
for (int i = 0; i < n; i++) {
d[i] = dis[0][i];
f[i] = 0;
G[i].clear();
}
d[0] = INF;
f[0] = -1;
vis[0] = true;
for (int i = 0; i < n - 1; i++) {
int x = 0;
for (int j = 1; j < n; j++)
if (!vis[j] && d[j] < d[x])
x = j;
vis[x] = true;
ans += d[x];
if (f[x] != -1) {
G[x].push_back(f[x]);
G[f[x]].push_back(x);
}
for (int j = 1; j < n; j++)
if (!vis[j] && d[j] > dis[x][j]) {
d[j] = dis[x][j];
f[j] = x;
}
}
return ans;
}
//得到dp[u][v]
int dfs1(int u, int fa, int root) {
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if (v != fa)
dp[root][u] = min(dp[root][u], dfs1(v, u, root));
}
if (fa != root) dp[root][u] = min(dp[root][u], dis[root][u]);
return dp[root][u];
}
//得到树边断裂后需要的最小权值边
int dfs2(int u, int fa, int root) {
int ans = dp[u][root];
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if (v != fa) ans = min(ans, dfs2(v, u, root));
}
return ans;
}
void solve() {
memset(dp, 0x3f, sizeof(dp));
ll MinTreeValue = prim();
double ans = 0;
for (int i = 0; i < n; i++)
dfs1(i, -1, i);
for (int i = 0; i < n; i++)
for (int j = 0; j < G[i].size(); j++) {
int v = G[i][j];
best[i][v] = best[v][i] = dfs2(v, i, i);
}
int u, v, c, q;
scanf("%d", &q);
for (int i = 0; i < q; i++) {
scanf("%d%d%d", &u, &v, &c);
if (f[u] != v && f[v] != u)
ans += MinTreeValue * 1.0;
else
ans += MinTreeValue * 1.0 - dis[u][v] + min(best[u][v], c);
}
printf("%.4f\n", ans / q);
}
int main() {
while (scanf("%d%d", &n, &m) != EOF && n + m ) {
init();
solve();
}
return 0;
}
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
#define N 3010
#define ll long long
const int INF = 1000000000;
int n, m, tot;
int dis[N][N], d[N], f[N], dp[N][N];
bool vis[N];
vector<int> G[N];
void init() {
memset(dis, 0x3f, sizeof(dis));
int u, v, c;
for (int i = 0; i < m; i++) {
scanf("%d%d%d", &u, &v, &c);
dis[u][v] = dis[v][u] = c;
}
}
ll prim() {
memset(vis, 0, sizeof(vis));
ll ans = 0;
for (int i = 0; i < n; i++) {
d[i] = dis[0][i];
f[i] = 0;
G[i].clear();
}
d[0] = INF;
f[0] = -1;
vis[0] = true;
for (int i = 0; i < n - 1; i++) {
int x = 0;
for (int j = 1; j < n; j++)
if (!vis[j] && d[j] < d[x])
x = j;
vis[x] = true;
ans += d[x];
if (f[x] != -1) {
G[x].push_back(f[x]);
G[f[x]].push_back(x);
}
for (int j = 1; j < n; j++)
if (!vis[j] && d[j] > dis[x][j]) {
d[j] = dis[x][j];
f[j] = x;
}
}
return ans;
}
//得到dp[u][v]
int dfs1(int u, int fa, int root) {
int res = INF;
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if (v == fa) continue;
int tmp = dfs1(v, u, root);
dp[u][v] = dp[v][u] = min(dp[u][v], tmp);
res = min(res, tmp);
}
if (fa != root) res = min(res, dis[root][u]);
return res;
}
void solve() {
memset(dp, 0x3f, sizeof(dp));
ll MinTreeValue = prim();
double ans = 0;
for (int i = 0; i < n; i++)
dfs1(i, -1, i);
int u, v, c, q;
scanf("%d", &q);
for (int i = 0; i < q; i++) {
scanf("%d%d%d", &u, &v, &c);
if (f[u] != v && f[v] != u)
ans += MinTreeValue * 1.0;
else
ans += MinTreeValue * 1.0 - dis[u][v] + min(dp[u][v], c);
}
printf("%.4f\n", ans / q);
}
int main() {
while (scanf("%d%d", &n, &m) != EOF && n + m ) {
init();
solve();
}
return 0;
}