最小生成树的变形(次小生成树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圆角框,圆角提示框
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- centos 部署 SparkR
---恢复内容开始--- 环境配置—— 操作系统:CentOS 6.5 JDK版本:1.7.0_67 Hadoop集群版本:CDH 5.3.0 安装过程—— 1.(1)安装R yum install ...
- 转载:IE下div使用margin:0px auto不居中的原因
转自:http://www.blogjava.net/sealyu/archive/2010/01/08/308640.html 一般在将div居中显示时,使用css: divX {margin:0 ...
- 最短路径问题-Floyd算法
概念 最短路径也是图的一个应用,即寻找图中某两个顶点的最短路径长度. 实际应用:例如确定某两个城市间的坐火车最短行车路线长度等. Floyd algorithm 中文名就是弗洛伊德算法. 算法思路:用 ...
- PHP json_decode 无法解析特殊问号字符
在通过别人接口请求信息的时候,偶尔会遇到由于部分字符,如以下情况,则通过json_decode是会返回null的 但是这种情况通常不是由于整体编码的问题,因为在解析的时候就是以utf-8的编码解析的 ...
- PHP简单的图片上传
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Windows 环境搭建Redis集群
环境以及引用资料 1.windows server 2008 r2 enterprise (木有办法,公司的服务器全是如此,就这种环境搭建吧) 2.redis官方资料下载: https://redi ...
- Oracle查询优化-多表查询
--合并结果集 --1.union all UNION ALL--单纯合并 ; --2.union UNION --将重复结果集合并 ; --------------使用命令窗口执行,查看union与 ...
- 谈谈我对Android View事件分发的理解
写这篇博客的缘由.近期因为项目中用到相似一个LinearLayout中水平布局中,有一个TextView和Button,然后对该LinearLayout布局设置点击事件.点击TextView能够触发该 ...
- Digest Authentication 摘要认证
“摘要”式认证( Digest authentication)是一个简单的认证机制,最初是为HTTP协议开发的,因而也常叫做HTTP摘要,在RFC2671中描述.其身份验证机制很简单,它采用杂凑式(h ...