poj1639 Picnic Planning Minimum Degree Limited Spanning Tree

Keywords: less

Origin: https://vjudge.net/problem/11062/origin

Topic: N-point M-side undirected graph, find a minimum spanning tree so that the degree of node 1 does not exceed the given k

The edge connected to Node 1 does not specify death, only if it is less than or equal to k, then it can start at k=1

First run the smallest spanning tree at all points except point 1. Note that all edges connected to point 1 will be disconnected at this time, then the original map may be divided into several separate smallest spanning trees. Use minlen[i] to save the minimum of all points to point 1 in the spanning tree numbered i, and minpoi[i] to save the smallest point to point 1 in the spanning tree numbered IThe point at which the value corresponds.The number here corresponds to the id generated by running Kruskal

First, to ensure the connectivity of the graph, the minpoi of each tree is connected to one point (that is, the point closest to one point in each minimum spanning tree is an edge with one point).

At this point we get a minimum spanning tree with a 1-point penetration of siz (siz refers to the minimum number of spanning trees with 1-point removed above).

Then if we add any more edges to the minimum spanning tree, it will form a closed loop, and then it will not be a tree. So if the minimum spanning tree is not the optimal spanning tree at this time, we need to add some edges and delete the same number of edges.

How to find the edges that should be deleted and added, using greedy ideas here.

Using the structure dp[i], there are three elements: fro, to, val, dp[i] to represent the information of the edge with the largest edge length from 1 node to I node (connecting fro and to edges with val, where fro and to have no meaning of direction)

Using m[i][j] to represent the distance between edges connecting points I and j, we delete one edge at a time and add one edge to change the weight of the whole tree growth to:

add=m[1][i]-dp[i].val (added edge weight-deleted edge weight)

Each time adds is found to be the smallest, if adds is greater than 0, then the tree is the best choice.

#include<iostream>
#include<cstdio>
#include<string>
#include<map>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 30;
const int INF = 0x3f3f3f3f;
map<string, int> M;
int tot, n, k, ans, siz;
int tre[maxn][maxn], m[maxn][maxn];
// tre[i][j] denotes i, is there an edge between J m[i][j] denotes i, and is the weight of the edge between J
int f[maxn]; //And Search Sets
int minpoi[maxn], minlen[maxn];
struct node {
	int fro, to, val;
	bool operator < (const node &e) const {
		return val < e.val;
	}
}e[10000], dp[10000];
int find(int x) {
	return f[x] == x ? x : f[x] = find(f[x]);
}
void Kruskal() {
	sort(e + 1, e + n + 1);
	for (int i = 1; i <= tot; i++) f[i] = i;
	for (int i = 1; i <= n; i++) {
		int &fro = e[i].fro, &to = e[i].to;
		if (fro == 1 || to == 1) continue;
		int fa = find(fro);
		int fb = find(to);
		if (fa == fb) continue;
		f[fa] = fb;
		tre[fro][to] = tre[to][fro] = 1;
		ans += e[i].val;
	}
}
void dfs(int fat, int now) {
	for (int i = 2; i <= tot; i++) {
		if (i == fat || tre[now][i] == 0) continue;
		if (dp[i].val == -1) {
			if (dp[now].val > m[now][i]) dp[i] = dp[now];
			else {
				dp[i].fro = now;
				dp[i].to = i;
				dp[i].val = m[now][i];
			}
		}
		dfs(now, i);
	}
}
void solve() {
	memset(minlen, INF, sizeof(minlen));
	int minn = INF;
	for (int i = 2; i <= tot; i++) { //Processing out minlen and minpoi arrays first
		if (m[1][i] != INF) {
			int f = find(i);
			if (minlen[f] > m[1][i]) {
				minlen[f] = m[1][i];
				minpoi[f] = i;
			}
		}
	}
	for (int i = 1; i <= tot; i++) { //Find the smallest edge from each spanning tree to point 1 and build it
		if (minlen[i] != INF) {
			siz++;
			tre[1][minpoi[i]] = tre[minpoi[i]][1] = 1;
			ans += minlen[i];
		}
	}
	for (int i = siz + 1; i <= k; i++) { 
		memset(dp, -1, sizeof(dp));
		dp[1].val = -INF; 
		for (int j = 2; j <= tot; j++) {//Edge already established should not be re-selected
			if (tre[1][j]) dp[j].val = -INF;
		}
		dfs(-1, 1); //dfs establishes dp array
		int aim;
		minn = INF;
		for (int j = 2; j <= tot; j++) { //Find minn Minimum
			if (minn > m[1][j] - dp[j].val) {
				minn = m[1][j] - dp[j].val;
				aim = j;
			}
		}
		if (minn > 0) break;
		tre[1][aim] = tre[aim][1] = 1;
		tre[dp[aim].to][dp[aim].fro] = tre[dp[aim].fro][dp[aim].to] = 0;
		ans += minn;
	}
}
int main() {
	cin >> n;
	tot = 0;
	M["Park"] = ++tot; 
	memset(m, INF, sizeof(m));
	for (int i = 1; i <= n; i++) {
		//e-saving is required by Kruskal and m-saving is required by subsequent deletion and edge addition.
		string s1, s2;
		cin >> s1 >> s2;
		if (!M.count(s1)) M[s1] = ++tot;
		if (!M.count(s2)) M[s2] = ++tot;
		e[i].fro = M[s1], e[i].to = M[s2];
		scanf("%d", &e[i].val);
		m[M[s1]][M[s2]] = m[M[s2]][M[s1]] = e[i].val; 
	}
	cin >> k;
	Kruskal();
	solve();
	printf("Total miles driven: %d\n", ans);
	return 0; 
}

 

Posted by athyzafiris on Sun, 08 Sep 2019 19:43:16 -0700