HDNOIP201206施工方案
难度级别:A; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

c国边防军在边境某处的阵地是由n个地堡组成的。工兵连受命来到阵地要进行两期施工。第一期的任务是挖掘暗道让所有地堡互联互通。

现已勘测设计了m条互不相交的暗道挖掘方案,如果这m条暗道都实施挖掘,肯定能达到互联互通的目的。

事实上,适当选择其中n-1个方案挖掘,就能实现互联互通,即从每个地堡出发都能到达其他任何一个地堡(允许经过别的地堡)。

连长精心谋算,在m个设计规划中选取了挖掘总距离最短且能保证互联互通的若干个暗道规划实施了挖掘,

完成了第一期的施工任务后又接受了第二期的施工任务,要求选择一个地堡进行扩建改造,使其能向每个地堡提供弹药。

为了让弹药供应更及时、更快捷,从改扩建的地堡到最远地堡的距离(称为最远输送距离)应当尽量小。

你的任务是先求出第一期施工挖掘的总距离,再求改扩建地堡最远输送距离的最小值。

输入
其中第一行是n和m,m>=n,下面的m行每行3个数xi、yi、zi,表示xi到yi的距离是zi,zi<1000000且m个距离互不相等
输出
两行各一个整数,第一行是第一期的挖掘总距离,第二行是最远输送距离的最小值。
输入示例
4 5
1 2 1
2 3 2
3 4 3
4 1 4
3 1 5
输出示例
6
3
其他说明
第一期挖掘1到2、2到3和3到4的3条暗道,第二期选择3号地堡进行改扩建,最远输送距离是3;60%的数据 n<10且m<20,80%的数据 n<1000且m<2000,100%的数据 n<100000且m<200000
 
 

第一问水水哒,直接MST即可。

第二问有两种做法:

做法一:可以猜想改建的地堡在直径上,因此两遍BFS即可

这个解法为什么是对的呢?我有一个绝妙的证明,但这里地方太小写不下。

#include<cstdio>
#include<cctype>
#include<queue>
#include<cstring>
#include<algorithm>
#define rep(s,t) for(int i=s;i<=t;i++)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
typedef long long LL;
const int maxn=;
const int maxm=;
struct Edge {
int u,v,w;
bool operator < (const Edge& ths) const {return w<ths.w;}
}e[maxm];
int n,m,pa[maxn];
int findset(int x) {return x==pa[x]?x:pa[x]=findset(pa[x]);}
LL ans1;
int first[maxn],to[maxn<<],next[maxn<<],dis[maxn<<],ToT;
void AddEdge(int u,int v,int w) {
to[++ToT]=v;dis[ToT]=w;next[ToT]=first[u];first[u]=ToT;
to[++ToT]=u;dis[ToT]=w;next[ToT]=first[v];first[v]=ToT;
}
int d[maxn],vis[maxn],p[maxn];
int bfs(int x) {
memset(vis,,sizeof(vis));
queue<int> Q;Q.push(x);vis[x]=;d[x]=;
while(!Q.empty()) {
x=Q.front();Q.pop();
ren if(!vis[to[i]]) vis[to[i]]=,Q.push(to[i]),d[to[i]]=d[x]+dis[i],p[to[i]]=x;
}
int ret=;
rep(,n) if(d[i]>d[ret]) ret=i;
return ret;
}
int main() {
n=read();m=read();
rep(,m) e[i].u=read(),e[i].v=read(),e[i].w=read();
rep(,n) pa[i]=i;
sort(e+,e+m+);
rep(,m) {
int x=findset(e[i].u),y=findset(e[i].v);
if(x!=y) pa[x]=y,AddEdge(e[i].u,e[i].v,e[i].w),ans1+=e[i].w;
}
printf("%lld\n",ans1);
int s=bfs(),t=bfs(s),x=t,ans2=1e9;
while(x!=s) {
ans2=min(ans2,max(d[t]-d[x],d[x]));
x=p[x];
}
printf("%d\n",ans2);
return ;
}

做法二:水水哒点分治就好啦。我们可以计算出每个点到其他点的最远距离,记为dp[i]。

当根节点为x时,我们可以更新所有子树的dp值与根节点的dp值,实现要正着反着各扫一遍。

#include<cstdio>
#include<cctype>
#include<queue>
#include<cstring>
#include<algorithm>
#define rep(s,t) for(int i=s;i<=t;i++)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
typedef long long LL;
const int maxn=;
const int maxm=;
struct Edge {
int u,v,w;
bool operator < (const Edge& ths) const {return w<ths.w;}
}e[maxm];
int n,m,pa[maxn];
int findset(int x) {return x==pa[x]?x:pa[x]=findset(pa[x]);}
LL ans1;
int first[maxn],to[maxn<<],next[maxn<<],dis[maxn<<],ToT;
void AddEdge(int u,int v,int w) {
to[++ToT]=v;dis[ToT]=w;next[ToT]=first[u];first[u]=ToT;
to[++ToT]=u;dis[ToT]=w;next[ToT]=first[v];first[v]=ToT;
}
int f[maxn],vis[maxn],dp[maxn],s[maxn],root,size;
void getroot(int x,int fa) {
s[x]=;int maxs=;
ren if(!vis[to[i]]&&to[i]!=fa) {
getroot(to[i],x);
s[x]+=s[to[i]];maxs=max(maxs,s[to[i]]);
}
f[x]=max(maxs,size-s[x]);
if(f[x]<f[root]) root=x;
}
int mxdep,dep2,A[maxn];
void dfs(int x,int fa,int dep) {
dp[x]=max(dp[x],mxdep+dep);dep2=max(dep,dep2);
ren if(!vis[to[i]]&&to[i]!=fa) dfs(to[i],x,dep+dis[i]);
}
void solve(int x) {
vis[x]=;mxdep=;int TAT=;
ren if(!vis[to[i]]) {
A[TAT++]=i;dep2=;
dfs(to[i],,dis[i]);
mxdep=max(mxdep,dep2);
}
dp[x]=max(dp[x],mxdep);mxdep=;
while(TAT--) {
dep2=;dfs(to[A[TAT]],,dis[A[TAT]]);
mxdep=max(mxdep,dep2);
}
ren if(!vis[to[i]]) {
f[]=size=s[to[i]];getroot(to[i],root=);
solve(root);
}
}
int main() {
n=read();m=read();
rep(,m) e[i].u=read(),e[i].v=read(),e[i].w=read();
rep(,n) pa[i]=i;
sort(e+,e+m+);
rep(,m) {
int x=findset(e[i].u),y=findset(e[i].v);
if(x!=y) pa[x]=y,AddEdge(e[i].u,e[i].v,e[i].w),ans1+=e[i].w;
}
printf("%lld\n",ans1);
f[]=size=n;getroot(,root=);
solve(root);
int ans2=1e9;
rep(,n) ans2=min(ans2,dp[i]);
printf("%d\n",ans2);
return ;
}

其实我认为第二个做法才是正解

COJ262 HDNOIP201206施工方案的更多相关文章

  1. HDNOIP201206施工方案

    HDNOIP201206施工方案 难度级别:A: 运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 c国边防军在边境某处的阵地是由n个地堡组成的. ...

  2. codevs——1700 施工方案第二季

    1700 施工方案第二季 2012年市队选拔赛北京  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解       题目描述 Description c国边防 ...

  3. codevs 1700 施工方案第二季

    1700 施工方案第二季 2012年市队选拔赛北京  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解       题目描述 Description c国边防 ...

  4. CODEVS——T 1700 施工方案第二季

    http://codevs.cn/problem/1700/ 2012年市队选拔赛北京  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解  查看运行结果   ...

  5. codevs1700 施工方案第二季

    题目描述 Description c国边防军在边境某处的阵地是由n个地堡组成的.工兵连受命来到阵地要进行两期施工. 第一期的任务是挖掘暗道让所有地堡互联互通.现已勘测设计了m条互不相交的暗道挖掘方案, ...

  6. 浅谈自我对git的初步认识

    本学期我们新增了一门课程,那就是软件工程,不知道为什么,感觉有种莫名的高大上.哈哈!难道是这个名称太抽象了吗?这个问题我感觉到后来肯定就明白了. 第一次博客,感觉好紧张哦,嘿嘿!老师让我们谈谈对git ...

  7. codevs与noi做题改错本目录

    从2016.2.13开始: 1.  排序超时的问题---------目录:-测试习题 2.  超高精度乘法超时问题-----------目录:高精度计算 算法:快速傅里叶算法. 压位算法 3. 高精度 ...

  8. js 数据获取

    http://www.cnhan.com/shantui/templates/MC500/TP001/js/template.js var qiaoContent="0";//0默 ...

  9. 杂项-建模:BIM

    ylbtech-杂项-建模:BIM 建筑信息模型是建筑学.工程学及土木工程的新工具.建筑信息模型或建筑资讯模型一词由Autodesk所创的.它是来形容那些以三维图形为主.物件导向.建筑学有关的电脑辅助 ...

随机推荐

  1. for循环,pydev提示未使用的变量,解决办法

    对于如下代码,pvdev会产生未使用变量的警告 for i in range(5): func() 解决办法: 把变量替换成下划线_,就不会生产告警了.改变后如下: for _ in range(5) ...

  2. Java最常用的变量定义汇总

    Java最常用的数据类型有基本数据类型,字符串对象,数组,基本数据类型又分为:数值型(包括整形和浮点型),字符型,布尔型,下面用一个简单的程序把这些数据类型汇总一下 public class Java ...

  3. Car的旅行路线(codevs 1041)

    题目描述 Description 又到暑假了,住在城市A的Car想和朋友一起去城市B旅游.她知道每个城市都有四个飞机场,分别位于一个矩形的四个顶点上,同一个城市中两个机场之间有一条笔直的高速铁路,第I ...

  4. ASP.NET之AreaRegistration

    ASP.NETMVC的AreaRegistration是用来干什么呢? 它是用来提供一个很好的接口让我们可以将Controller定义在其他的Library项目中,这主要可以用来解决模块化开发:一般情 ...

  5. 我的MySQL5.6免安装版配置过程

    最近打算学习MySQL,第一步就是安装.下载到一个面安装版.解压到我的D盘的mysql目录. 弄了一个最简单的配置文件.目录中只有一个my-default.ini,基本没啥用.在网上弄了一个my.in ...

  6. 【Ubuntu日常技巧】【解决】Ubuntu 16 右上角的音量调节通知框不停地闪烁问题

    一. 先上干货 解决问题 1.1 安装工具alsa-tools-gui sudo apt-get install alsa-tools-gui 1.2 通过hdajackretask设置 直接执行命令 ...

  7. oracle 10g 学习之客户端安装和配置(2)

    概述 Oracle 数据库是一种网络上的数据库, 它在网络上支持多用户, 支持服务器/客户机等部署(或配置) 服务器与客户机是软件概念, 它们与计算机硬件不存在一一对应的关系. 即: 同一台计算机既可 ...

  8. [编辑器] Tab转换成空格

    Notepad++: 设置 -> 首选项 -> 制表符设置 怎样设置EditPlus中Tab用空格替换http://jingyan.baidu.com/article/63f236280b ...

  9. Xamarin.Android开发实践(十七)

    Xamarin.Android之定位 一.前言 打开我们手中的应用,可以发现越来越多的应用使用了定位,从而使我们的生活更加方便,所以本章我们将学习如何在Xamarin中进行定位的开发. 二.准备工作 ...

  10. 微信聊天测试脚本 wx_sample.php

    <?php </FuncFlag>                             </xml>);         curl_setopt($ch, CURLO ...