[Kruskal][jzyzoj1224]:连接格点

  犯了个很智障的错误,本来以为是读入出了问题,结果往kruskal函数里一看。。。。1-2=-1,-1*1000+1=-999,所以RE了。。。下面给出题面:

  

  由题意我们好像看不出来这是个最小生成树。最初我以为这是一道纯贪心就能AC的题,然而仔细画了画图发现并不是这样,如果用贪心的方法算每列上存在的边的条数并不行,因为一列上可以不存在任意一条边,但是如果说通过一个点生成的长边通向这一列上的另外一点的话,这两点之间是不需要再建立一条边的

  这样的话我们可以用图的思想:已经连通的几条边我们可以看做是权值为0的边,还未连通的边我们可以看做是横向权值为1,纵向权值为2的边,然后建图就可以。不过建图的时候需要注意要把二维变为一维

  但是如果将所有的可建立的边记录起来的话不免有些麻烦,我们可以想一个更简便的方法。

  还是贪心的思想:我们先读入已经连好的边,因为这些连好的边的权值为0,所以我们优先用并查集将这两个点合并,即这两点之间不需要再连额外的边,然后在逐个合并的时候不需要再建立边,因为每条边都是横向或是纵向的,而连接纵向的边的权值相对较小,所以我们可以优先连接纵向的边,然后连接横向的边,这样就能解决这个问题了。

  注意记录已经连接的边数,如果边数等于点数-1的话就不需要再连接了,此时一定为最优解。

  代码如下:

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 int m,n,father[1000010],ans=0,len=0,sum=0;
 5 int getfather(int x)
 6 {
 7     int y=x;
 8     while (father[y]!=y)    y=father[y];
 9     while (father[x]!=x)
10     {
11         int temp=father[x];
12         father[x]=y;
13         x=temp;
14     }
15     return y;
16 }
17
18 void init()
19 {
20     scanf("%d%d",&m,&n);
21     for (int i=1;i<=m*n;i++)    father[i]=i;
22     int x1,y1,x2,y2,i=0;
23     while    (scanf("%d%d%d%d",&x1,&y1,&x2,&y2)!=EOF)
24     {
25         i++;
26         int f1=getfather((x1-1)*n+y1),f2=getfather((x2-1)*n+y2);
27         if (f1!=f2)
28         {
29             father[f1]=f2;
30             sum++;
31         }
32     }
33 }
34
35 void kruskal()
36 {
37     for (int i=1;i<=n;i++)
38         for (int j=2;j<=m;j++)//枚举纵向的边,n要放在外层,注意j应当从2开始枚举,防止数组越界
39         {
40             if (sum==m*n-1)    return;        //判断是否已建立足够的边
41             int f1=getfather((j-1)*n+i),f2=getfather((j-2)*n+i);    //注意二维变一维
42             if (f1!=f2)
43             {
44                 father[f1]=f2;
45                 ans++;    sum++;
46             }
47         }
48     for (int i=1;i<=m;i++)
49         for (int j=2;j<=n;j++)//枚举横向的边,n放在内层,j从2开始,防止枚举上一行最后一列到本行第一列的边
50         {
51             if (sum==m*n-1)    return;        //判断是否已建立足够的边
52             int f1=getfather((i-1)*n+j),f2=getfather((i-1)*n+j-1);
53             if (f1!=f2){
54                 father[f1]=f2;
55                 ans+=2; sum++;
56             }
57         }
58 }
59
60 int main()
61 {
62     init();
63     kruskal();
64     printf("%d\n",ans);
65     return 0;
66 }

AC代码

时间: 2024-12-24 19:10:07

[Kruskal][jzyzoj1224]:连接格点的相关文章

算法提高课——图论

图论难点:问题的转化和抽象(可看成特殊的某一类DP) 图论与DP的联系: DP问题(从集合角度分析最优化问题)可以看成从F(0,0).F(0,1).F(1,2)......F(0,m)到F(n,m)的最长路.因此DP问题可以转化为拓扑图(一般DP问题的状态间无环)上的最短(长)路. 当DP依赖关系不具有拓扑序时(即存在环时),可以将其转化为最短路,也可以用高斯消元. //TLE的原因常常是没有memsert //st数组在不同算法中的用法: 单源最短路的建图方式 AcWing 1129. 热浪

洛谷 P2735 电网 Electric Fences Label:计算几何--皮克定理

题目描述 在本题中,格点是指横纵坐标皆为整数的点. 为了圈养他的牛,农夫约翰(Farmer John)建造了一个三角形的电网.他从原点(0,0)牵出一根通电的电线,连接格点(n,m)(0<=n<32000,0<m<32000),再连接格点(p,0)(p>0),最后回到原点. 牛可以在不碰到电网的情况下被放到电网内部的每一个格点上(十分瘦的牛).如果一个格点碰到了电网,牛绝对不可以被放到该格点之上(或许Farmer John会有一些收获).那么有多少头牛可以被放到农夫约翰的电网

P2735 电网 Electric Fences

题目描述 在本题中,格点是指横纵坐标皆为整数的点. 为了圈养他的牛,农夫约翰(Farmer John)建造了一个三角形的电网.他从原点(0,0)牵出一根通电的电线,连接格点(n,m)(0<=n<32000,0<m<32000),再连接格点(p,0)(p>0),最后回到原点. 牛可以在不碰到电网的情况下被放到电网内部的每一个格点上(十分瘦的牛).如果一个格点碰到了电网,牛绝对不可以被放到该格点之上(或许Farmer John会有一些收获).那么有多少头牛可以被放到农夫约翰的电网

一本通基础篇图论

1341 一笔画问题 1 #include <cstdio> 2 #include <algorithm> 3 #include <stack> 4 using namespace std; 5 const int MAXN = 110000,MAXM = 510000; 6 stack <int> stk; 7 int head[MAXN],ind[MAXN]; 8 int to[MAXM],nxt[MAXM],idx[MAXM]; 9 int cnt,n

hdu 5253 连接的管道(kruskal)(2015年百度之星程序设计大赛 - 初赛(2))

连接的管道 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1323    Accepted Submission(s): 519 Problem Description 老 Jack 有一片农田.以往几年都是靠天吃饭的. 可是今年老天格外的不开眼.大旱.所以老 Jack 决定用管道将他的全部相邻的农田全部都串联起来.这样他就能够从远处

Kruskal 2015百度之星初赛2 HDOJ 5253 连接的管道

题目传送门 1 /* 2 最小生成树(Kruskal):以权值为头,带入两个端点,自然的排序;感觉结构体的并查集很好看 3 注意:题目老头要的是两个农田的高度差,中文水平不好,题意理解成和平均值的高度差! 4 */ 5 #include <cstdio> 6 #include <algorithm> 7 #include <cstring> 8 #include <cmath> 9 #include <vector> 10 #include &l

实习小白笔记一(鼠标悬停、获取多选、提交修改、layer页面、单元格文字长度、json、分页、左连接)

①easyui 当鼠标悬停显示单元格信息: $(this).datagrid('doCellTip',{'max-width':'600px','delay':300}); ②jquery 获取checkbox多个被选元素 1 var swa = new Array(); 2 $("input[name='mainten.softwareReason']:checked").each(function(){ 3 swa.push($(this).val()); 4 }); 5 var

SecureCRT远程连接Linux下的sqlplus中退格键不能使用之解决方法

^H不是H键的意思,是backspace 主要是当你的终端backspace有问题的时候才需要设置 在linux环境下使用sqlplus,在回删(backspace)时往往会出现 一串的乱码.出现乱码是由于oracle的sqlplus不使用gnu的readline库造成的. 解决方法有2种: 1. 要使用回删键(backspace)时,同时按住ctrl键 2. 设定环境变量 在bash下:$ stty erase ^H 或者把 stty erase ^? 添加到.bash_profile中. 在

最小生成树 Prim(普里姆)算法和Kruskal(克鲁斯特尔)算法

Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小.该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现:并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现:1959年,艾兹格·迪科斯彻再次发现了该算法.因此,在某些场