HDU 4081 Excited!次小生成树与树状dp

#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1010;
const double INF = 1e14;
struct Point
{
	int x, y, cost;
};
int pre[MAX_N], used[MAX_N][MAX_N], visit[MAX_N], city;
Point point[MAX_N];
double edge[MAX_N][MAX_N], Max[MAX_N][MAX_N], cost[MAX_N], res, sum;
void init()
{
	memset(used, 0, sizeof(used));
	memset(visit, 0, sizeof(visit));
	memset(Max, 0, sizeof(Max));
	sum = 0, res = -1;
	for (int i = 1; i <= city; i++)
		cost[i] = edge[1][i], pre[i] = 1;
}
void prim()
{
	init();
	visit[1] = 1;
	for (int i = 1; i <= city; i++)
	{
		double min = INF;
		int chios = -1;
		for (int j = 2; j <= city; j++)
			if (!visit[j] && cost[j] < min)
				chios = j, min = cost[j];
		if (chios != -1)
		{
			sum += cost[chios];
			used[chios][pre[chios]] = used[pre[chios]][chios] = 1;
			visit[chios] = 1;
			for (int k = 1; k <= city; k++)
			{
				if (visit[k] && k != chios)
					Max[chios][k] = Max[k][chios] = max(Max[k][pre[chios]], cost[chios]);
				if (!visit[k] && edge[chios][k] < cost[k])
					cost[k] = edge[chios][k], pre[k] = chios;
			}
		}
	}
}
double solve()
{
	res = -1;
	for (int i = 1; i <= city; i++)
		for (int j = 1; j <= city; j++)
			if (i != j)
				if (used[i][j])
					res = max(res, (double)(point[i].cost + point[j].cost) / (sum - edge[i][j]));
				else  res = max(res, (double)(point[i].cost + point[j].cost) / (sum - Max[i][j]));
	return res;
}
int main(int argc, char const *argv[])
{
	int kase;
	cin >> kase;
	while (kase--)
	{
		cin >> city;
		for (int i = 1; i <= city; i++)
			cin >> point[i].x >> point[i].y >> point[i].cost;
		for (int i = 1; i <= city; i++)
		{
			edge[i][i] = 0;
			for (int j = i + 1; j <= city; j++)
				edge[i][j] = edge[j][i] = sqrt((double)pow((point[i].x - point[j].x), 2) + pow((point[i].y - point[j].y), 2));
		}
		prim();
		cout << setiosflags(ios::fixed) << setprecision(2) << solve() << endl;
	}
	return 0;
}

我就不说题意了,为了使A/B最大,就应该是B越小,故可以先求出n个点的最小生成树。因此,可以枚举每一条边,假设最小生成树的值是B, 而枚举的那条边长度是edge[i][j],  如果这一条边已经是属于最小生成树上的,那么最终式子的值是A/(B-edge[i][j])。如果这一条不属于最小生成树上的, 那么添加上这条边,就会有n条边,那么就会使得有了一个环,为了使得它还是一个生成树,就要删掉环上的一棵树。 为了让生成树尽量少,那么就要删掉除了加入的那条边以外,权值最大的那条路径。 假设删除的那个边的权值是Max[i][j], 那么就是A/(B-Max[i][j]).
这题的关键也在于怎样求出次小生成树;
先用prim求出最小生成树T.在prim的同时,用一个矩阵max[u][v] 记录 在T中连结任意两点u,v的唯一的路中权值最大的那条边的权值.这是很容易做到的,因为prim是每次增加一个结点s, 而设已经标号了的结点集合为W, 则W中所有的结点到s的路中的最大权值的边就是当前加入的这条边.

来自http://www.cnblogs.com/wally/archive/2013/02/04/2892194.html

很好的题,还可以用树状dp做,挖坑代填

http://www.cnblogs.com/ACMan/archive/2012/10/07/2714502.html

你可能感兴趣的:(HDU 4081 Excited!次小生成树与树状dp)