Spanning Tree algorithm to improve the minimum variance (enum + Kruskal)

Questions spanning tree algorithm to improve the minimum variance

Resource constraints
Time limit: 1.0s memory limit: 256.0MB
problem description
given weighted undirected graph, find the minimum spanning tree of a variance.
Input format
input multiple sets of test data. The first row N, M, followed by points and edges. Side, and the right to the next M rows, each row of three integers U, V, W is, represents a linking U, V value W. FIG ensure communication. n = m = 0 marks the end of the test file.
Output Format
For each test, the minimum output variance, rounded to 0.01. Sample according to the output format.
Sample input
. 4. 5
. 1. 1 2
2 2. 3
. 3. 4 2
. 4. 1. 1
2. 4. 3
. 4. 6
. 1. 1 2
2 2. 3
. 3. 4. 3
. 4. 1. 1
2. 4. 3
. 1. 3. 3
0 0
Sample Output
Case. 1: 0.22
Case 2: 0.00
data size and conventions
1 <= U, V <= N <= 50, N-1 <= M <= 1000,0 <= W <= 50. Does not exceed five groups.

Interpretations
concept minimum variance tree is, the n FIG nodes, the pick n-1 sides, first make this FIG communication, then the variance of which the n-1 weights edges to the minimum, calculating the variance of the the formula is:
Here Insert Picture Description
as can be seen, the mean variance with the relevant sides, but there is a difficulty is, with the addition of side, the average of dynamically changing sides will, is not conducive to problem-solving.
There is an idea: Solving the total weight of the edges in a known and minimal variance, which is easy to achieve, because the sum of the edge weights are known, and the number (n) of known nodes, then also the number of edges We know (n-1), so that the average value of the edge to know, so that each side of the mean squares is a constant of not moving. At this point we then process the minimum spanning tree, is not the edge weights of the original weight, but its weight and the square of the mean difference, then follow the steps of the minimum spanning tree determined minimum variance .
AC code is as follows: using the Kruskal algorithm for the MST, used to set and check code from https://www.cnblogs.com/asuml/p/6798307.html

#include <cstdio>
#include <algorithm>
using namespace std;

double const MAX = 10000000000000.0;
int n, m, tmp[1005], fa[55];
double ans;

struct Edge
{
    int u, v;
    double w, val;
}e[1005];

bool cmp(Edge a, Edge b)
{
    return a.w < b.w;
}

void UF_set(int n)
{
    for(int i = 1; i <= n; i++)
        fa[i] = i;
}

int Find(int x)
{
    return x == fa[x] ? x : fa[x] = Find(fa[x]);
}

void Union(int a, int b)
{
    int r1 = Find(a);
    int r2 = Find(b);
    if(r1 != r2)
        fa[r2] = r1;
}

void Kruskal(int sum)
{
    UF_set(n);
    int cnt = 0;
    double f_all = 0;
    double all = 0;
    double ave = sum * 1.0 / (n - 1);
    for(int i = 0; i < m; i++)
        e[i].w = (e[i].val - ave) * (e[i].val - ave);
    sort(e, e + m, cmp);
    for(int i = 0; i < m; i++)
    {
        int u = e[i].u;
        int v = e[i].v;
        if(Find(u) != Find(v))
        {
            Union(u, v);
            f_all += e[i].w;
            all += e[i].val;
            cnt ++;
        }
        if(cnt == n - 1)
            break;
    }
    if((int)all == sum)
        ans = min(ans, f_all);
}

int main()
{
    int ca = 1;
    while(scanf("%d %d", &n, &m) != EOF && (m + n))
    {
        // if(n == 1 || n == 2)
        // {
        //     printf("0.00\n");
        //     continue;
        // }
        int minv = 0;
        int maxv = 0;
        ans = MAX;
        for(int i = 0; i < m; i++)
        {
            scanf("%d %d %lf", &e[i].u, &e[i].v, &e[i].val);
            tmp[i] = e[i].val;
        }
        sort(tmp, tmp + m);
        for(int i = 0; i < n - 1; i++)
            minv += tmp[i];
        for(int i = m - 1; i > m - n; i--)
            maxv += tmp[i];
        for(int i = minv; i <= maxv; i++)
            Kruskal(i);
        ans = ans / (n - 1);
        printf("Case %d: %.2f\n", ca++, ans);
    }
}

As can be seen, press the edge weights descending enumeration, and then take the side where the n-1, n-1 edges which maximum value is taken from the rear forward, the minimum value is taken from front to back, then the cost of the minimum spanning tree will be in between the two, he dwells on, if there is such a MST is found, then find the smallest variance in this case, the smallest in the final to take all possible variance.

PS. Editors have a practice, no AC, the function of little , or would like to share with you:
we have selected a point (a), with its one side as the starting side, and then use Prim minimum spanning tree algorithm, with the priority queue, queue each time taken from the side, updating the currently selected mean side, and then out from the queue each time the mean difference is minimal side, access to all known nodes. This also needs to traverse from the other side of a departure, because I do not know which one side consisting of MST, but certainly there is an edge belongs to the MST, or a node on isolated. Then a minimum value of variance in these types of situations.
code show as below:

#include<bits/stdc++.h>
using namespace std;

struct edge {
	int from;
	int to;
	int we;
	edge(int _from = 0, int _to = 0, int _we = 0) { from = _from; to = _to; we = _we; }
};
vector<edge> V[51];
vector<edge> choose;
bool vis[51];
int N, M;
float fenzi, fenmu, shang;
float ans;


struct cmp {
	bool operator()(edge a, edge b) {
		return  abs(a.we - shang) > abs(b.we - shang);
	}
};


void prim() {
	ans = 1e6;
	for (int i = 0; i < V[1].size(); i++) {

		priority_queue<edge, vector<edge>, cmp > Q;
		memset(vis, 0, sizeof(vis));
		fenzi = 0;
		fenmu = 0;
		choose.clear();

		int code = 1;
		Q.push(V[1][i]);
		vis[1] = 1;
		while (!Q.empty()) {
			edge tmp = Q.top();
			Q.pop();
			if (code) {
				code = 0;
				for (int j = 0; j < V[1].size(); j++)
					if (j != i)
						Q.push(V[1][j]);
			}
			if (vis[tmp.to])
				continue;

			vis[tmp.to] = 1;
			choose.push_back(tmp);
			fenmu++;
			fenzi += tmp.we;
			shang = fenzi / fenmu;

			for (int j = 0; j < V[tmp.to].size(); j++) {
				Q.push(V[tmp.to][j]);
			}

		}
		float h = 0;
		for (int j = 0; j < choose.size(); j++) {
			h += (choose[j].we - shang)*(choose[j].we - shang);
		}
		ans = min(ans, h / fenmu);
	}
}

int main() {
	int a, b, c;
	int ccase = 0;
	while (scanf("%d%d", &N, &M) && N&&M) {
		ccase++;
		for (int i = 0; i < 51; i++)
			V[i].clear();
		for (int i = 0; i < M; i++) {
			scanf("%d%d%d", &a, &b, &c);
			V[a].push_back(edge(a, b, c));
			V[b].push_back(edge(b, a, c));
		}

		prim();

		printf("Case %d: %.2f\n", ccase, ans);
	}
	return 0;
}
Published 23 original articles · won praise 2 · Views 1212

Guess you like

Origin blog.csdn.net/Raymond_YP/article/details/104581098