MST + 树形 dp

时间:2023-03-10 07:50:04
MST + 树形 dp
Genghis Khan(成吉思汗)(1162-1227), also known by his birth name Temujin(铁木真) and temple name Taizu(元太祖), was the founder of the Mongol Empire and the greatest conqueror in Chinese history. After uniting many of the nomadic tribes on the *n steppe, Genghis Khan founded a strong cavalry equipped by irony discipline, sabers and powder, and he became to the most fearsome conqueror in the history. He stretched the empire that resulted in the conquest of most of Eurasia. The following figure (origin: Wikipedia) shows the territory of Mongol Empire at that time.

MST + 树形 dp

Our story is about Jebei Noyan(哲别), who was one of the most famous
generals in Genghis Khan’s cavalry. Once his led the advance troop to
invade a country named Pushtuar. The knights rolled up all the cities in
Pushtuar rapidly. As Jebei Noyan’s advance troop did not have enough
soldiers, the conquest was temporary and vulnerable and he was waiting
for the Genghis Khan’s reinforce. At the meantime, Jebei Noyan needed to
set up many guarders on the road of the country in order to guarantee
that his troop in each city can send and receive messages safely and
promptly through those roads.

There were N cities in Pushtuar and there were bidirectional roads
connecting cities. If Jebei set up guarders on a road, it was totally
safe to deliver messages between the two cities connected by the road.
However setting up guarders on different road took different cost based
on the distance, road condition and the residual armed power nearby.
Jebei had known the cost of setting up guarders on each road. He wanted
to guarantee that each two cities can safely deliver messages either
directly or indirectly and the total cost was minimal.

Things will always get a little bit harder. As a sophisticated
general, Jebei predicted that there would be one uprising happening in
the country sooner or later which might increase the cost (setting up
guarders) on exactly ONE road. Nevertheless he did not know which road
would be affected, but only got the information of some suspicious road
cost changes. We assumed that the probability of each suspicious case
was the same. Since that after the uprising happened, the plan of
guarder setting should be rearranged to achieve the minimal cost, Jebei
Noyan wanted to know the new expected minimal total cost immediately
based on current information.

InputThere are no more than 20 test cases in the input.

For each test case, the first line contains two integers N and M
(1<=N<=3000, 0<=M<=N×N), demonstrating the number of cities
and roads in Pushtuar. Cities are numbered from 0 to N-1. In the each of
the following M lines, there are three integers x
i, y
i and c
i(c
i<=10
7), showing that there is a bidirectional road between x
i and y
i, while the cost of setting up guarders on this road is c
i. We guarantee that the graph is connected. The total cost of the graph is less or equal to 10
9.

The next line contains an integer Q (1<=Q<=10000) representing
the number of suspicious road cost changes. In the following Q lines,
each line contains three integers X
i, Y
i and C
i showing that the cost of road (X
i, Y
i) may change to C
i (C
i<=10
7). We guarantee that the road always exists and C
i is larger than the original cost (we guarantee that there
is at most one road connecting two cities directly). Please note that
the probability of each suspicious road cost change is the same.

OutputFor each test case, output a real number demonstrating the
expected minimal total cost. The result should be rounded to 4 digits
after decimal point.

Sample Input

3 3
0 1 3
0 2 2
1 2 5
3
0 2 3
1 2 6
0 1 6
0 0

Sample Output

6.0000

Hint

The initial minimal cost is 5 by connecting city 0 to 1 and city 0 to 2. In the first suspicious case, the minimal total cost is increased to 6;
the second case remains 5; the third case is increased to 7. As the result, the expected cost is (5+6+7)/3 = 6.

题意:给你一个无向图,每次更换一条边的长度,一定是增加,问每次让图连通的最小的花费。

思路分析:先求一个 mst, 然后dp预处理一个去掉边(i,j)后此图还是连通的最小的花费。

代码示例:

int n, m;
int edge[3005][3005];
int f[3005];
struct node
{
int u, v, c; node(int _u=0, int _v=0, int _c=0):u(_u), v(_v), c(_c){}
bool operator< (const node &pp){
return c < pp.c;
}
}pre[3005*3005];
vector<int>ve[3005]; int fid(int x){
if (x != f[x]) f[x] = fid(f[x]);
return f[x];
}
int cost;
bool pt[3005][3005]; void kru(){
sort(pre+1, pre+1+m);
cost = 0; for(int i = 1; i <= m; i++){
int u = pre[i].u, v = pre[i].v, c = pre[i].c;
int fu = fid(u), fv = fid(v);
if (fu != fv){
f[fu] = fv;
cost += c;
ve[u].push_back(v);
ve[v].push_back(u);
pt[u][v] = pt[v][u] = true;
}
}
}
int dp[3005][3005]; int dfs(int cur, int x, int fa){ //dfs求的是它的所有孩子结点与 cur 连接的最小值
int res = inf; for(int i = 0; i < ve[x].size(); i++){
int to = ve[x][i];
if (to == fa) continue; int mid = dfs(cur, to, x);
res = min(res, mid);
dp[x][to] = dp[to][x] = min(dp[to][x], mid); // 注意这里是mid,指的是去掉与当前结点相连的边后其所指的再次联通两部分的最小花费
}
if (cur != fa){ // 只有当不相等的时候指的才是其不在最小生成树上的边
res = min(res, edge[cur][x]);
}
return res;
} void init() {
memset(edge, inf, sizeof(edge));
memset(pt, false, sizeof(pt));
memset(dp, inf, sizeof(dp));
for(int i = 1; i <= n; i++) ve[i].clear(), f[i] = i;
}
int x, y, z, q; int main() {
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout); while(~scanf("%d%d", &n, &m) && n+m){
init();
for(int i = 1; i <= m; i++){
scanf("%d%d%d", &x, &y, &z);
x++, y++;
edge[x][y] = edge[y][x] = z;
pre[i] = node(x, y, z);
} kru();
for(int i = 1; i <= n; i++) dfs(i, i, -1);
scanf("%d", &q);
double sum = 0;
for(int i = 1; i <= q; i++){
scanf("%d%d%d", &x, &y, &z);
x++, y++;
if (!pt[x][y]) sum += 1.0*cost;
else {
sum += 1.0*(cost-edge[x][y])+1.0*min(z, dp[x][y]);
}
}
printf("%.4lf\n", sum/q);
}
return 0;
}