uvalive 4960 Sensor Network

news/2024/10/31 3:22:55/

题意:

给出一个无向图,求一个生成树使得这个生成树的最大边与最小边之差最小,输出这个最小的差值。n的最大值为350。

思路:

这题不看题解想破头也不知道怎么写Orz。

暴力的做法是可以从大到小枚举边作为最小边的权值,求MST,但是复杂度达到了O(n^4),很显然会T。

考虑在kruskal算法加边的时候,当两个点在同一个连通分量的时候,加入这条边会形成环,这个时候就把环中的最小边去掉,剩下的边就尽可能达到了最大,当前加入的边设为Ea也最大的,然后再找现在生成树中的最小边Eb;当有n-1条边的时候,就形成了一个生成树,就可以利用Ea – Eb去更新答案。

最重要的两个过程是找环和加边。

判断环,用了LCA的思想,但并不是倍增,而是纯粹暴力的dfs。对于一条边的两个点假设为x和y,首先从一个点x开始访问,直到访问到它的祖先,即满足条件par[x] == x,标记这个过程中的所有点;然后从y开始访问,直到访问到它的祖先(同上)或者它自己或某一个祖先被标记了为止,若y访问到祖先都没有点被标记,那么就说明x和y没有公共祖先,那么它们就不在同一个连通分量中,加入这条边就不会形成环。

若找到了环,那么就要求这个环中边的最小值,求法很自然,遍历从x出发到lca的所有边,遍历从y出发到lca的所有边,找出其中的最小边,之后去掉这条边,去掉这条边有个技巧,假设最小边的非父亲点为u,那么去掉这条边时,令par[u] = u,这条边就被去掉了。之后再找最小边即可。

之后就是加边的过程。并查集加边是启发式合并,但是这题的加边是有方向的加边

假设两个点x和y,如果有其中一个点就是祖先,那么就把这个点连到另外一个点上(如x为祖先点,那么令par[x] = y)。

但是如果两个点都不是祖先,那么就要考虑如何合并,因为一个点不可能同时有两个父亲

可以考虑从一个点开始访问,直到访问到祖先,将路径上的点全部按访问的顺序记录在一个vector中,之后逆向加边。

再把这个点连到另一个点上。如图:

合并前:

合并后:

最后再把这个点(从这个点开始访问的)连接到另一个点上,加边就完成了。

枚举边的复杂度为O(n^2),找环和加边的复杂度为O(n),所以总的复杂度为O(n^3)。

感谢MZjj帮我debug!

代码:

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <vector>
  6 using namespace std;
  7 
  8 const int N = 400;
  9 const int inf = 0x3f3f3f3f;
 10 
 11 struct edge
 12 {
 13     int x,y,w;
 14     
 15     edge(){};
 16     
 17     edge(int a,int b,int c)
 18     {
 19         x = a;
 20         y = b;
 21         w = c;
 22     }
 23 };
 24 
 25 vector<edge> es;
 26 
 27 int par[N];
 28 int n,m;
 29 int dis[N][N];
 30 bool vis[N];
 31 int num;
 32 int Minedge;
 33 struct edge minedge;
 34 
 35 bool cmp(edge aa,edge bb)
 36 {
 37     return aa.w < bb.w;
 38 }
 39 
 40 void init(void)
 41 {
 42     for (int i = 0;i < n;i++) par[i] = i;
 43     
 44     num = 0;
 45     
 46     es.clear();
 47     
 48     memset(dis,inf,sizeof(dis));
 49     
 50     Minedge = inf;
 51 }
 52 
 53 int LCA(int x,int y)
 54 {
 55     memset(vis,0,sizeof(vis));
 56     
 57     while (1)
 58     {
 59         vis[x] = 1;
 60         
 61         if (x == par[x]) break;
 62         
 63         x = par[x];
 64     }
 65     
 66     while (!vis[y] && y != par[y])
 67     {
 68         y = par[y];
 69     }
 70     
 71     if (!vis[y]) return -1;
 72     
 73     return y;
 74 }
 75 
 76 void findcycle(int k)
 77 {
 78     int x = es[k].x,y = es[k].y;
 79     
 80     int lca = LCA(x,y);
 81     
 82     if (lca == -1) return;
 83     
 84     minedge.w = inf;
 85     
 86     while (x != par[x] && x != lca)
 87     {
 88         if (dis[x][par[x]] < minedge.w)
 89         {
 90             minedge = edge(par[x],x,dis[x][par[x]]);
 91         }
 92         
 93         x = par[x];
 94     }
 95     
 96     while (y != par[y] && y != lca)
 97     {
 98         if (dis[y][par[y]] < minedge.w)
 99         {
100             minedge = edge(par[y],y,dis[y][par[y]]);
101         }
102         
103         y = par[y];
104     }
105     
106     par[minedge.y] = minedge.y;
107     
108     Minedge = inf;
109     
110     for (int i = 0;i < n;i++)
111     {
112         Minedge = min(dis[par[i]][i],Minedge);
113     }
114     
115     num--;
116 }
117 
118 void adde(int k)
119 {
120     int x = es[k].x,y = es[k].y;
121     
122     if (x == par[x]) par[x] = y;
123     else if (y == par[y]) par[y] = x;
124     else
125     {
126         vector<int> v;
127         
128         while (1)
129         {
130             v.push_back(x);
131             
132             if (x == par[x]) break;
133             
134             x = par[x];
135         }
136         
137         for (int i = v.size() - 1;i > 0;i--) par[v[i]] = v[i-1];
138         
139         par[es[k].x] = es[k].y;
140     }
141     
142     num++;
143     
144     Minedge = min(Minedge,es[k].w);
145 }
146 
147 int main()
148 {
149     while (scanf("%d",&n) && n)
150     {
151         scanf("%d",&m);
152         
153         init();
154         
155         for (int i = 0;i < m;i++)
156         {
157             int a,b,c;
158             
159             scanf("%d%d%d",&a,&b,&c);
160             
161             es.push_back(edge(a,b,c));
162         }
163         
164         for (int i = 0;i < m;i++)
165         {
166             int x = es[i].x,y = es[i].y;
167             
168             dis[x][y] = dis[y][x] = es[i].w;
169         }
170         
171         sort(es.begin(),es.end(),cmp);
172         
173         int ans = inf;
174         
175         for (int i = 0;i < m;i++)
176         {
177             findcycle(i);
178             adde(i);
179             
180             if (num == n - 1) 
181             {
182                 //cout << es[i].w << " ** " << Minedge << endl;
183                 ans = min(ans,es[i].w - Minedge);
184             }
185         }
186         
187         cout << ans << endl;
188     }
189     
190     return 0;
191 }

 

转载于:https://www.cnblogs.com/kickit/p/8808886.html


http://www.ppmy.cn/news/460657.html

相关文章

4960x支持服务器内存吗,提升不到10%:i7-4960x六核处理器实测

泡泡网CPU频道4月26日 Intel的新一代发烧处理器Ivy Bridge-E将在11月份发布,而到那个时候,Sandy Bridge-E平台将会坚守长达两年时间,这在顶级产品上是很不可思议的。正因为如此,很多发烧友对Ivy Bridge-E都期待万分,特别是它还继续兼容LGA2011接口和X79芯片组。 那么Ivy B…

0008-TIPS-2020-hxp-kernel-rop : bypass-FGKASLR-with-unaffected_gadgets

利用 CTF-WKI中描述中的缺点&#xff1a;.text 节区不参与函数随机化。因此&#xff0c;一旦知道其中的某个地址&#xff0c;就可以获取该节区所有的地址。有意思的是系统调用的入口代码都在该节区内&#xff0c;主要是因为这些代码都是汇编代码。此外&#xff0c;该节区具有以…

国产麒麟服务器等保二级 配置规范(二)

一、redis的配置规范 1.1 禁止以root账号运行redis服务 以下Linux 命令操作创建了一个无 home 目录权限&#xff0c;且无法登录的普通账号redis。 #useradd -M -s /sbin/nologin redis 修改服务允许和配置文件权限&#xff1a; #setsid sudo -u redis /usr/bin/redis-serer /e…

Kafka源码解析之索引

Kafka源码解析之索引 索引结构 Kafka有两种类型的索引&#xff1a; TimeIndex: 根据时间戳索引&#xff0c;可以通过时间查找偏移量所在位置&#xff0c;目录下以.timeindex结尾Index: 根据偏移量索引&#xff0c;.index结尾 构建索引时机 由log.index.interval.bytes 参…

Android——如何在电脑里找到手机中的图片或者视频

1.先让你的手机与你的电脑进行多媒体的连接 2.首先找到你的Android的SDK目录&#xff0c;然后进入platform-tools目录下&#xff0c;然后shift鼠标右键&#xff0c;选择在此处打开cmd或Powershell窗口&#xff0c;然后执行adb shell命令即可 3.然后我们在手机中随便找一个图片…

老电脑如何利用云服务器提升性能,把旧电脑变成云电脑?让手机运行大型PC游戏...

相信很多人家里有电脑&#xff0c;有的闲置了下来&#xff0c;也有还在继续超龄服役的&#xff0c;只不过性能已经跟不上了&#xff0c;平时应付下办公和看视频还是可以的。对于大型游戏&#xff0c;想都别想。 其实云电脑并不是硬件而是软件&#xff0c;能让老旧电脑通过连接云…

在手机与计算机之间进行文件传输的方式,电脑和手机传输文件方法_电脑和手机如何传文件-win7之家...

我们会经常使用手机和电脑之间互相传输文件&#xff0c;一般来说都是用usb数据线来传输&#xff0c;要是数据线坏了的时候该怎么办&#xff0c;我们也可以用一些软件来进行传输&#xff0c;那么电脑和手机如何传文件呢&#xff0c;下面小编给大家分享电脑和手机传输文件的方法步…