最小生成树的变形(次小生成树hdu4081)
Qin Shi Huang's National Road System
conquered all six other kingdoms and became the first emperor of a unified China in 221 BC. That was Qin dynasty ---- the first imperial dynasty of China(not to be confused with the Qing Dynasty, the last dynasty of China). So Ying Zheng named himself "Qin
Shi Huang" because "Shi Huang" means "the first emperor" in Chinese.
Qin Shi Huang undertook gigantic projects, including the first version of the Great Wall of China, the now famous city-sized mausoleum guarded by a life-sized Terracotta Army, and a massive national road system. There is a story about the road system:
There were n cities in China and Qin Shi Huang wanted them all be connected by n-1 roads, in order that he could go to every city from the capital city Xianyang.
Although Qin Shi Huang was a tyrant, he wanted the total length of all roads to be minimum,so that the road system may not cost too many people's life. A daoshi (some kind of monk) named Xu Fu told Qin Shi Huang that he could build a road by magic and that
magic road would cost no money and no labor. But Xu Fu could only build ONE magic road for Qin Shi Huang. So Qin Shi Huang had to decide where to build the magic road.Qin Shi Huang wanted the total length of all
none magic roads to be as small as possible, but Xu Fu wanted the magic road to benefit as many people as possible ---- So Qin Shi Huang decided that the value of A/B (the ratio of A to B) must be the maximum,which A is the total population of the two
cites connected by the magic road, and B is the total length of none magic roads.
Would you help Qin Shi Huang?
A city can be considered as a point, and a road can be considered as a line segment connecting two points.
For each test case:
The first line is an integer n meaning that there are n cities(2 < n <= 1000).
Then n lines follow. Each line contains three integers X, Y and P ( 0 <= X, Y <= 1000, 0 < P < 100000). (X, Y) is the coordinate of a city and P is the population of that city.
It is guaranteed that each city has a distinct location.
2
4
1 1 20
1 2 30
200 2 80
200 1 100
3
1 1 20
1 2 30
2 2 40
65.00
70.00
题意:在一个二维坐标系中给出n个城市的坐标以及该城市的人口,前期秦始皇为了节省钱,但又要联通所有的城市,就建立了一颗最小生成树,保证道路和最短,后来有一个法师拥有一种技能,他能造一条路仅且一条,这条路不需要花费任何费用,秦始皇想让除了这条路的其他路的总长度(B)最小,而那个法师想让这条魔幻路连接的两个城市的总人口(A)最多,所以怎样建立虚拟路才能使A/B的值最大;
分析:此题有两种方法:
(1)要保证A/B最大,这条魔幻路肯定取代的是最小生成树里的某条路,首先建立一颗最小生成树(sum)然后枚举删除最小生成树里的每一条边i,此时形成两个集合,然后分别从两个集合各找一个最大的人口数x和y,然后此时的A/B=(x+y)/(sum-e[i].w);
比较大小即可;有可能最小生成树的会存在多个,那么为什么随便取一种就行呢?首先想想当最小生成树有多个的时候,他们的权值和一定是一样的,例如下图:
首先介绍等效边:例如给出的最小生成树中,(1,3)和(2,3)就是等效边,就是说当联通两个集合的边的权值是一样的他们就是等效边,现在就好理解上面的疑问了,当删除(2,3)这条边时,形成两个集合,假如最小生成树有(1,3)这条边,删除后形成的两个集合是相同的,并不影响最终的结果;
(2)首先用dij求出任意一颗最小生成树,同时记录任意两个点在生成树路径中的最大边权,然后枚举每一条边,当边在生成树里面则比值是:
(p[i].z+p[j].z)/(ans-G[i][j]);否则是:(p[i].z+p[j].z)/(ans-maxd[i][j]);取最大值即可;
程序(1);
#include"stdio.h"
#include"string.h"
#include"iostream"
#include"map"
#include"string"
#include"queue"
#include"stdlib.h"
#include"math.h"
#define M 1009
#define eps 1e-8
#define inf 1000000000
#define mod 1000000000
#define INF 1000000000
using namespace std;
struct node
{
int u,v,next;
double w;
}e[M*M],edge[M*2];
int t,head[M],dis[M];
double maxdis;
double prep[M];
struct st
{
double x,y,z;
}p[M];
int cmp(const void *a,const void *b)
{
return (*(struct node*)a).w>(*(struct node*)b).w?1:-1;
}
void init()
{
t=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v,double w)
{
edge[t].u=u;
edge[t].v=v;
edge[t].w=w;
edge[t].next=head[u];
head[u]=t++;
}
int f[M];
int finde(int x)
{
if(x!=f[x])
f[x]=finde(f[x]);
return f[x];
}
void dfs(int u,int f)//深搜查找最大值
{
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(f!=v)
{
dfs(v,u);
}
}
if(maxdis<p[u].z)
maxdis=p[u].z;
}
int mp[M];
int main()
{
int T,i,j,n,m;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z);
m=0;
for(i=1;i<=n;i++)
{
for(j=i+1;j<=n;j++)
{
double L=sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y));
e[m].u=i;
e[m].v=j;
e[m].w=L;
m++;
}
}
qsort(e,m,sizeof(e[0]),cmp);
int kk=0;
double sum=0;
init();
for(i=1;i<=n;i++)
f[i]=i;
for(i=0;i<m;i++)
{
int a=finde(e[i].u);
int b=finde(e[i].v);
if(a!=b)
{
mp[kk++]=i;
sum+=e[i].w;
f[a]=b;
add(e[i].u,e[i].v,e[i].w);
add(e[i].v,e[i].u,e[i].w);//建立最小生成树
}
if(kk==n-1)
break;
}
double ans=0;
for(i=0;i<kk;i++)//枚举最小生成树的边
{
double A=0,B;
int u=e[mp[i]].u;
int v=e[mp[i]].v;
maxdis=0;
dfs(v,u);
A+=maxdis;
maxdis=0;
dfs(u,v);
A+=maxdis;
B=sum-e[mp[i]].w;
ans=max(ans,A/B);
}
printf("%.2lf\n",ans);
}
return 0;
}
程序(2):
#include"stdio.h"
#include"string.h"
#include"math.h"
#define inf 100000000
#define M 1111
int use[M],pre[M],vis[M][M];
double G[M][M],dis[M],maxd[M][M];
double max(double a,double b)
{
return a>b?a:b;
}
double min(double a,double b)
{
return a<b?a:b;
}
double dij(int u,int n)
{
int i,j;
double ans=0;
memset(use,0,sizeof(use));
memset(maxd,0,sizeof(maxd));//记录不在任意两点在在生成树的路径中的最长边
memset(vis,0,sizeof(vis));//标记边是否在生成树里面
for(i=1;i<=n;i++)
{
dis[i]=G[u][i];
pre[i]=u;//记录父节点
}
dis[u]=0;
use[u]=1;
for(i=1;i<n;i++)
{
double mini=inf;
int tep=-1;
for(j=1;j<=n;j++)
{
if(!use[j]&&dis[j]<mini)
{
mini=dis[j];
tep=j;
}
}
if(tep==-1)break;
use[tep]=1;
vis[tep][pre[tep]]=vis[pre[tep]][tep]=1;
ans+=mini;
for(j=1;j<=n;j++)
{
if(!use[j]&&dis[j]>G[tep][j])
{
dis[j]=G[tep][j];
pre[j]=tep;
}
if(j!=tep)
maxd[tep][j]=maxd[j][tep]=max(mini,maxd[pre[tep]][j]);//更新
}
}
return ans;
}
struct node
{
double x,y,z;
}p[M];
double pow(double x)
{
return x*x;
}
double Len(node a,node b)
{
return sqrt(pow(a.x-b.x)+pow(a.y-b.y));
}
int main()
{
int T,n,i,j;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z);
for(i=1;i<=n;i++)
{
G[i][i]=0;
for(j=i+1;j<=n;j++)
G[i][j]=G[j][i]=Len(p[i],p[j]);
}
double ans=dij(1,n);
//printf("%.2lf\n",ans);
double maxi=0;
for(i=1;i<=n;i++)
{
for(j=i+1;j<=n;j++)
{
if(vis[i][j])
maxi=max(maxi,(p[i].z+p[j].z)/(ans-G[i][j]));
else
maxi=max(maxi,(p[i].z+p[j].z)/(ans-maxd[i][j]));
}
}
printf("%.2lf\n",maxi);
}
return 0;
}
最小生成树的变形(次小生成树hdu4081)的更多相关文章
- [kuangbin带你飞]专题八 生成树 - 次小生成树部分
百度了好多自学到了次小生成树 理解后其实也很简单 求最小生成树的办法目前遇到了两种 1 prim 记录下两点之间连线中的最长段 F[i][k] 之后枚举两点 若两点之间存在没有在最小生成树中的边 那么 ...
- [BZOJ1977]严格次小生成树
[问题描述] 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等. 正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成 ...
- poj1679 The Unique MST(判定次小生成树)
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 23180 Accepted: 8235 D ...
- vijos1070 新年趣事之游戏 - 次小生成树
传送门 题目大意: 求原图的最小生成树,和次小生成树. 题目分析: kruskals求mst(\(O(mlogm)\)) 考虑次小生成树暴力的做法,因为次小生成树总是由最小生成树删掉一条边并添加一条边 ...
- P4180 [BJWC2010]严格次小生成树
P4180 [BJWC2010]严格次小生成树 P4180 题意 求出一个无向联通图的严格次小生成树.严格次小生成树的定义为边权和大于最小生成树的边权和但不存在另一棵生成树的边权和在最小生成树和严格次 ...
- hdu4081 次小生成树变形
pid=4081">http://acm.hdu.edu.cn/showproblem.php?pid=4081 Problem Description During the Warr ...
- HDU4081 Qin Shi Huang's National Road System —— 次小生成树变形
题目链接:https://vjudge.net/problem/HDU-4081 Qin Shi Huang's National Road System Time Limit: 2000/1000 ...
- URAL 1416 Confidential --最小生成树与次小生成树
题意:求一幅无向图的最小生成树与最小生成树,不存在输出-1 解法:用Kruskal求最小生成树,标记用过的边.求次小生成树时,依次枚举用过的边,将其去除后再求最小生成树,得出所有情况下的最小的生成树就 ...
- (poj)1679 The Unique MST 求最小生成树是否唯一 (求次小生成树与最小生成树是否一样)
Description Given a connected undirected graph, tell if its minimum spanning tree is unique. Definit ...
随机推荐
- 设计中最常用的CSS选择器
准确而简洁的运用CSS选择器会达到非常好的效果.我们不必通篇给每一个元素定义类(class)或ID,通过合适的组织,可以用最简单的方法实现同样的效果.在实际工作中,最常用的选择器有以下五类: 一.标签 ...
- sparkr——报错
> sc <- sparkR.init() Re-using existing Spark Context. Please stop SparkR with sparkR.stop() o ...
- javascript控制服务器控件实例一
最近多个页面需要加载一些下拉列表框,供用户选择,原来都是在服务器端进行加载应运用.最后由于 业务逻辑方面的考虑,需要将DropDownList的部分功能放到客户端实现.现在下拉列表的功能使用起来感 觉 ...
- e673. Getting Amount of Free Accelerated Image Memory
Images in accelerated memory are much faster to draw on the screen. However, accelerated memory is t ...
- CentOS基础命令大全
1.关机 (系统的关机.重启以及登出 ) 的命令 shutdown -h now 关闭系统(1) init 0 关闭系统(2) telinit 0 关闭系统(3) shutdown -h hours: ...
- 【Java NIO深入研究3】文件锁
1.1概述——文件锁 文件锁定初看起来可能让人迷惑.它 似乎 指的是防止程序或者用户访问特定文件.事实上,文件锁就像常规的 Java 对象锁 — 它们是 劝告式的(advisory) 锁.它们不阻止任 ...
- BIEE多层表头报表的制作方法
使用BIEE制作多层表头的报表大致分为以下的几种办法. 1.双层表头 这种比较容易实现,只需要在表格属性中勾选作为单独的行显示即可.这样通过修改文件夹标题,就可以实现双层表头的制作 2.多层表头的制作 ...
- 【ML】scikit-learn-book
http://nbviewer.ipython.org/github/gmonce/scikit-learn-book/tree/master/
- java程序后台报错java.net.SocketException: Too many open files
问题描述: 今天一个同事反映程序有问题,让帮忙查看后台日志,发现后台日志报错的信息如下: java.net.SocketException: Too many open files at java.n ...
- 【Android开发】如何设计开发一款Android App
本文从开发工具选择,UI界面.图片模块.网络模块.数据库产品选择.性能.安全性等几个方面讲述了如果开发一个Android应用.现在整理出来分享给广大的Android程序员. 开发工具的选择 开发工具我 ...