• 题目链接:

    https://www.luogu.org/problemnew/show/P2212

  • 思路:

    一道最小生成树裸题(最近居然变得这么水了),但是因为我太蒻,搞了好久,不过借此加深了对最小生成树的认识.

    首先这明显是个稠密图,有\(\sum_{n-1}^{i=1}i=n*(n-1)/2\)条边,看起来\(Prim\)会明显优于\(Kruskal\),于是这道题我用了三种方法

  • \(Kruskal\)

    简单易懂,简洁优美 耗时/内存 344ms, 24343KB

    代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <cctype>
#define ri register int
#define ll long long
using namespace std;
const int maxn=2005;
const int inf=192681792;
struct Edge{
int u,v,dis;
bool operator <(const Edge& b)const{
return dis<b.dis;
}
}edge[19260817];//边数不要设小了
int n,c,tot=0;
int px[maxn],py[maxn];
int fa[maxn];
int get(int x){
if(fa[x]!=x)fa[x]=get(fa[x]);
return fa[x];
}
inline void kruskal(){
int u,v,dis;
int cnt=0,ans=0;
for(ri i=1;i<=n;i++){
fa[i]=i;
}
for(ri i=1;i<=tot;i++){
u=edge[i].u,v=edge[i].v;
u=get(u),v=get(v);
if(u!=v){
fa[u]=v;
ans+=edge[i].dis;
cnt++;
}
if(cnt==n-1)break;
}
if(cnt==n-1)printf("%d",ans);
else puts("-1");
return ;
}
int main(){
scanf("%d %d",&n,&c);
for(ri i=1;i<=n;i++){
scanf("%d %d",&px[i],&py[i]);
for(ri j=1;j<i;j++){
int d=(px[i]-px[j])*(px[i]-px[j])+(py[i]-py[j])*(py[i]-py[j]);
if(d>=c){
edge[++tot].u=i,edge[tot].v=j,edge[tot].dis=d;
}
}
}
sort(edge+1,edge+1+tot);
kruskal();
return 0;
}
  • \(Prim+Priority\_queue\)优化

    说到\(Prim\)就不得不提,觉得网上挺多\(Prim\)堆优化代码都是假的。

    \(Prim\)的原理是找到连接生成树点集中一点与非生成树点集中一点的最小边权,将其加入答案,于是我们用\(vis[]\)数组标记该点是否处在生成树点集中,\(d[x]\)记录x到非生成树点集中一点的最短边权,或者是该点加入生成树点集中时的边权。

    于是我们将一个节点加入生成树点集中时,就要通过此点进行一次类似松弛的操作,更新该点出边的\(d[]\)值,最终答案就是所有点\(d[]\)值之和。

    然后网上很多代码都没有这种类似操作,我也不太懂他们的原理

    但是呢,在此题上运用上述算法的\(Prim\)会快100+ms,应该是更优的

    同时此题还要判断-1情况(即无法联通),我们只需判断非生成树点集集合大小

    与无法加入生成树点集集合大小是否相等(即\(d[x]=INF\)的点的个数)就可以了.

    代码: 耗时/内存 336ms, 46703KB

    有趣的是仅比\(Kruskal\)快了10ms左右

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <vector>
#include <queue>
#define ri register int
#define ll long long
using namespace std;
const int maxn=2005;
const int inf=192681792;
int n,c;
int px[maxn],py[maxn];
struct Edge{
int ne,to,dis;
}edge[19260817];
int h[maxn],num_edge=0;
struct Ele{
int ver,dis;
bool operator <(const Ele &b)const{
return dis>b.dis;
}
Ele(int x,int y){ver=x,dis=y;}
};
inline void add_edge(int f,int t,int dis){
edge[++num_edge].ne=h[f];
edge[num_edge].to=t;
edge[num_edge].dis=dis;
h[f]=num_edge;
}
inline void prim(){
priority_queue<Ele>a;
int d[maxn],u,v,dis,cnt=0,ans=0,q=n-1;
bool vis[maxn];
for(ri i=1;i<=n;i++){d[i]=inf,vis[i]=0;}
d[1]=0;
while(a.size())a.pop();
a.push(Ele(1,0));
while(a.size()){
u=a.top().ver,dis=a.top().dis,a.pop();
while(vis[u]){
u=a.top().ver,dis=a.top().dis,a.pop();
}
//ans+=dis,
cnt++,vis[u]=1;
//cout<<cnt<<endl;
if(cnt==n-1)break;
for(ri i=h[u];i;i=edge[i].ne){
v=edge[i].to;
if(!vis[v]&&d[v]>edge[i].dis){
if(d[v]==inf)q--;
d[v]=edge[i].dis;
a.push(Ele(v,d[v]));
}
}
if(q==n-cnt)break;
}
for(ri i=1;i<=n;i++)ans+=d[i];
if(cnt==n-1)printf("%d\n",ans);
else puts("-1");
return ;
}
int main(){
scanf("%d %d",&n,&c);
for(ri i=1;i<=n;i++){
scanf("%d %d",&px[i],&py[i]);
for(ri j=1;j<i;j++){
int d=(px[i]-px[j])*(px[i]-px[j])+(py[i]-py[j])*(py[i]-py[j]);
if(d>=c){
add_edge(i,j,d);
add_edge(j,i,d);//edge[++tot].u=i,edge[tot].v=j,edge[tot].dis=d;
}
}
}
prim();
return 0;
}
  • \(Prim+\)手写堆

    其他一样,将POI改成了手写堆,同时我发现手写堆\(Heap[]\)若用结构体时用\(swap()\)会出现玄学错误

    代码:耗时/内存 424ms, 46867KB

    比POI还更慢,可见O2的力量

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cctype>
#define ri register int
#define ll long long
using namespace std;
const int maxn=2005;
const int inf=192681792;
int n,c;
int px[maxn],py[maxn];
struct Edge{
int ne,to,dis;
}edge[19260817];
int h[maxn],num_edge=0;
struct Ele{
int ver,dis;
Ele(int x,int y){ver=x,dis=y;}
Ele(){;}
};
struct S_Heap{
int heap[1926817],ver[1926817];
int n;
inline void up(int k){
int f=(k>>1);
while(k>1){
if(heap[k]<heap[f]){
swap(heap[k],heap[f]);
swap(ver[k],ver[f]);
k=f,f=(k>>1);
}
else break;
}
return ;
}
inline void push(int v,int di){
ver[++n]=v;
heap[n]=di;
up(n);
}
inline void down(int fa){
int s=(fa<<1);
while(s<=n){
if(s<n&&heap[s]>heap[s+1])s++;
if(heap[s]<heap[fa]){
swap(heap[s],heap[fa]);
swap(ver[s],ver[fa]);
fa=s,s=(fa<<1);
}
else break;
}
return ;
}
inline void pop(){
heap[1]=heap[n];
ver[1]=ver[n--];
down(1);
return ;
}
};
inline void add_edge(int f,int t,int dis){
edge[++num_edge].ne=h[f];
edge[num_edge].to=t;
edge[num_edge].dis=dis;
h[f]=num_edge;
}
inline void prim(){
S_Heap a;//priority_queue<Ele>a;
int d[maxn],u,v,dis,cnt=0,ans=0,q=n-1;
bool vis[maxn];
for(ri i=1;i<=n;i++){d[i]=inf,vis[i]=0;}
d[1]=0;
a.push(1,0);
while(a.n){
u=a.ver[1],dis=a.heap[1],a.pop();
while(vis[u]){
u=a.ver[1],dis=a.heap[1],a.pop();
}
cnt++,vis[u]=1;
if(cnt==n-1)break;
for(ri i=h[u];i;i=edge[i].ne){
v=edge[i].to;
if(!vis[v]&&d[v]>edge[i].dis){
if(d[v]==inf)q--;
d[v]=edge[i].dis;
a.push(v,d[v]);
}
}
if(q==n-cnt)break;
}
for(ri i=1;i<=n;i++)ans+=d[i];
if(cnt==n-1)printf("%d\n",ans);
else puts("-1");
return ;
}
int main(){
scanf("%d %d",&n,&c);
for(ri i=1;i<=n;i++){
scanf("%d %d",&px[i],&py[i]);
for(ri j=1;j<i;j++){
int d=(px[i]-px[j])*(px[i]-px[j])+(py[i]-py[j])*(py[i]-py[j]);
if(d>=c){
add_edge(i,j,d);
add_edge(j,i,d);//edge[++tot].u=i,edge[tot].v=j,edge[tot].dis=d;
}
}
}
prim();
return 0;
}

luogu题解 P2212 【浇地Watering the Fields】的更多相关文章

  1. 洛谷 P2212 [USACO14MAR]浇地Watering the Fields 题解

    P2212 [USACO14MAR]浇地Watering the Fields 题目描述 Due to a lack of rain, Farmer John wants to build an ir ...

  2. P2212 [USACO14MAR]浇地Watering the Fields

    P2212 [USACO14MAR]浇地Watering the Fields 题目描述 Due to a lack of rain, Farmer John wants to build an ir ...

  3. 洛谷——P2212 [USACO14MAR]浇地Watering the Fields

    P2212 [USACO14MAR]浇地Watering the Fields 题目描述 Due to a lack of rain, Farmer John wants to build an ir ...

  4. P2212 [USACO14MAR]浇地Watering the Fields 洛谷

    https://www.luogu.org/problem/show?pid=2212 题目描述 Due to a lack of rain, Farmer John wants to build a ...

  5. 洛谷 P2212 [USACO14MAR]浇地Watering the Fields

    传送门 题解:计算欧几里得距离,Krusal加入边权大于等于c的边,统计最后树的边权和. 代码: #include<iostream> #include<cstdio> #in ...

  6. [USACO14MAR]浇地Watering the Fields

    题目描述 Due to a lack of rain, Farmer John wants to build an irrigation system tosend water between his ...

  7. BZOJ3479: [Usaco2014 Mar]Watering the Fields

    3479: [Usaco2014 Mar]Watering the Fields Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 81  Solved: ...

  8. BZOJ 3479: [Usaco2014 Mar]Watering the Fields( MST )

    MST...一开始没注意-1结果就WA了... ---------------------------------------------------------------------------- ...

  9. bzoj 3479: [Usaco2014 Mar]Watering the Fields

    3479: [Usaco2014 Mar]Watering the Fields Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 174  Solved ...

随机推荐

  1. Spring Boot学习笔记(1)

    @SpringBootApplication用于注解Spring启动类,如下所示 @SpringBootApplication public class Application { public st ...

  2. mysql常用操作与日志

    在linux上的mysql命令 mysql -e "mysql内部命令" #可在外部显示myslq内的输出,-e可跟多条命令用;隔开 在mysql内的mysql命令 system ...

  3. js常用遍历汇总

    1, for(let i of Array) for( let i of arr){ console.log(i); } ES6新增的,i代表每次循环Array的值,相当于Array[0]到Array ...

  4. Appium移动自动化测试(四)之元素定位

    做过UI自动化测试的童鞋都会发现, 在上一篇文章中居然没有万能定位方式Xpath. 是滴, 确实没有! ADT自带的uiautomatorviewer里面并没有属性xpath, 如果我们需要的话,还需 ...

  5. 阶段3 3.SpringMVC·_07.SSM整合案例_09.ssm整合之Spring整合MyBatis框架配置事务

    spring加入声明式的事物 配置事物 配置事物管理器 需要一个dataSource,引入上面的dataSource 配置事务通知 引入上面的transactionManager事物管理器 find开 ...

  6. Python学习笔记:读取Excel的xlrd模块

    一.安装xlrd 可以使用命令行安装也可使用pycharm进行安装 表示xlrd库已经安装成功,安装成功后,我们就可以导入使用了. 二.xlrd说明 (1.单元格常用的数据类型包括 0:empty(空 ...

  7. spring-boot集成5:集成jrebel实现热加载

    Why Jrebel? 使用jrebel可以方便的实现spring-boot项目的热部署,直接reload更改的class,无需重启,提升开发效率. 1.安装jrebel插件 在idea中安装jreb ...

  8. docker 入门 命令

    docker 命令 docker images 镜像列表 docker ps 服务列表 docker 隐藏打包文件 .dockerignore .git node_modules npm-debug. ...

  9. Spark内核源码解析

    1.spark内核架构常用术语 Application:基于spark程序,包含一个driver program(客户端程序)和多个executeor(线程) Driver Progrom:代表着sp ...

  10. CTF—攻防练习之HTTP—SQL注入(SSI注入)

    主机:192.168.32.152 靶机:192.168.32.161 ssI是赋予html静态页面的动态效果,通过ssi执行命令,返回对应的结果,若在网站目录中发现了.stm .shtm .shtm ...