• 题目链接:

    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. 黑马lavarel教程---13、分页

    黑马lavarel教程---13.分页 一.总结 一句话总结: - lavarel里面的分页操作和tp里面的分页操作几乎是一模一样的 - 控制器:$data=Lesson::paginate(2); ...

  2. vue图片的处理技巧

    我们想用 post 向后台发送字符串类型的数据:我们可以不适用 data 来进行数据传输,而是用 params 来进行数据传输 代码的简洁之道:分模块化书写: vue 里面提供对图片的监听事件:loa ...

  3. CentOS7 开机启动脚本与命令后台运行

    一.& 在 Linux 命令后加上 &  可以在后台运行 二.nohup 对 SIGHUP 信号免疫,对 SIGINT 信号不免疫,可用 shopt | grep hup 查看. 当关 ...

  4. Volley源码分析

    取消请求的源码分析: public void cancelAll(RequestFilter filter) { synchronized (mCurrentRequests) { for (Requ ...

  5. Python中的变量和作用域详解

    Python中的变量和作用域详解 python中的作用域分4种情况: L:local,局部作用域,即函数中定义的变量: E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部 ...

  6. iOS UItextView监听输入特定字符跳转页面选择选项返回

    今天有朋友问我一个需求的实现,于是自己写了一个Demo简单的实现了一下: 需求是: 1>比如: 检测用户输入"A"字符串,跳转页面选择选项,将选择的选项放置textView里 ...

  7. linux常用、常见错误

    1.md5加密使用 oppnssl md5 加密字符串的方法 [root@lab3 ~]# openssl //在终端中输入openssl后回车. OpenSSL> md5 //输入md5后回车 ...

  8. [LeetCode] 697. Degree of an Array 数组的度

    Given a non-empty array of non-negative integers nums, the degree of this array is defined as the ma ...

  9. pytorch神经网络层搭建方法

    神经网络层的搭建主要是两种方法,一种是使用类(继承torch.nn.Moudle),一种是使用torch.nn.Sequential来快速搭建. 1)首先我们先加载数据: import torchim ...

  10. 联想H430怎么清除cmos密码?

    联想H430怎么清除cmos密码? 方法一:长时间对cmos放电 首先断掉主机电源,然后找到主板上的纽扣电池,将电池小心取出,然后使用一金属导体,短接电池座中的正负极,这样也可达到快速放电的目的. 有 ...