次小生成树学习小记 Hdu 4081 Qin Shi Huang's National Road System (模板)
2014-05-15 20:43
459 查看
以下学习资料转自 http://blog.csdn.net/Jarily/article/details/8883858 代码根据自己的风格重写了,算是个模板吧。
2014-08-05补充资料
次小生成树问题探讨 - DM张朋飞 - 博客园
算法引入:
设G=(V,E,w)是连通的无向图,T是图G的一棵最小生成树;
如果有另一棵树T1,满足不存在树T’,ω(T’)<ω(T1),则称T1是图G的次小生成树;
算法思想:
邻集的概念:由T进行一次可行交换得到的新的生成树所组成的集合,称为树T的邻集,记为N(T);
设T是图G的最小生成树,如果T1满足ω(T1)=min{ω(T’)|T’∈N(T)},则T1是G的次小生成树;
首先先求该图的最小生成树T,时间复杂度O(Vlog2V+E);
然后,求T的邻集中权值和最小的生成树,即图G 的次小生成树;
如果只是简单的枚举,复杂度很高;
首先枚举两条边的复杂度是O(VE),再判断该交换是否可行的复杂度是O(V),则总的时间复杂度是O(V2E);
分析可知,每加入一条不在树上的边,总能形成一个环,只有删去环上的一条边,才能保证交换后仍然是生成树;
而删去边的权值越大,新得到的生成树的权值和越小,可以以此将复杂度降为O(VE);
更好的方法:首先做一步预处理,求出树上每两个结点之间的路径上的权值最大的边;
然后枚举图中不在树上的边,有了预处理,就可以用O(1)的时间得到形成的环上的权值最大的边;
预处理:因为是一棵树,只要简单的BFS即可,预处理所要的时间复杂度为O(V2);
题意:
有n个城市,秦始皇要修用n-1条路把它们连起来,要求从任一点出发,都可以到达其它的任意点,秦始皇希望这所有n-1条路长度之和最短;
然后徐福突然有冒出来,说是他有魔法,可以不用人力、财力就变出其中任意一条路出来;
秦始皇希望徐福能把要修的n-1条路中最长的那条变出来,但是徐福希望能把要求的人力数量最多的那条变出来;
对于每条路所需要的人力,是指这条路连接的两个城市的人数之和;
秦始皇给出了一个公式A/B,A是指要徐福用魔法变出的那条路所需人力,
B是指除了徐福变出来的那条之外的所有n-2条路径长度之和,选使得A/B值最大的那条;
分析:
为了使的A/B值最大,首先是需要是B尽量要小,所以可先求出n个城市的最小生成树;
然后就是决定要选择哪一条边用徐福的魔法来变;
可以枚举每一条边,假设最小生成树的值是Mst,而枚举的那条边长度是G[i][j],
如果这一条边已经是属于最小生成树上的,那么最终式子的值是A/(Mst-graph[i][j]);
如果这一条不属于最小生成树上的,那么添加上这条边,就会有n条边,那么就会使得有了一个环;
为了使得它还是一个生成树,就要删掉环上的一条边,为了让生成树的权值尽量小,那么就要删掉除了加入的那条边以外,权值最大的那条路径;
假设删除的那个边的权值是path[i][j],那么就是A/(Mst-path[i][j]);
解这题的关键也在于怎样求出次小生成树,具体实现时,更简单的方法是从每个节点i遍历整个最小生成树;
定义path[i][j]为从i到j的路径上最大边的权值,遍历图求出path[i][j]的值;
然后对于添加每条不在最小生成树中的边(i,j),新的生成树权值之和就是Mst+graph[i][j]–path[i][j],其最小值则为次小生成树;
2014-08-05补充资料
次小生成树问题探讨 - DM张朋飞 - 博客园
算法引入:
设G=(V,E,w)是连通的无向图,T是图G的一棵最小生成树;
如果有另一棵树T1,满足不存在树T’,ω(T’)<ω(T1),则称T1是图G的次小生成树;
算法思想:
邻集的概念:由T进行一次可行交换得到的新的生成树所组成的集合,称为树T的邻集,记为N(T);
设T是图G的最小生成树,如果T1满足ω(T1)=min{ω(T’)|T’∈N(T)},则T1是G的次小生成树;
首先先求该图的最小生成树T,时间复杂度O(Vlog2V+E);
然后,求T的邻集中权值和最小的生成树,即图G 的次小生成树;
如果只是简单的枚举,复杂度很高;
首先枚举两条边的复杂度是O(VE),再判断该交换是否可行的复杂度是O(V),则总的时间复杂度是O(V2E);
分析可知,每加入一条不在树上的边,总能形成一个环,只有删去环上的一条边,才能保证交换后仍然是生成树;
而删去边的权值越大,新得到的生成树的权值和越小,可以以此将复杂度降为O(VE);
更好的方法:首先做一步预处理,求出树上每两个结点之间的路径上的权值最大的边;
然后枚举图中不在树上的边,有了预处理,就可以用O(1)的时间得到形成的环上的权值最大的边;
预处理:因为是一棵树,只要简单的BFS即可,预处理所要的时间复杂度为O(V2);
题意:
有n个城市,秦始皇要修用n-1条路把它们连起来,要求从任一点出发,都可以到达其它的任意点,秦始皇希望这所有n-1条路长度之和最短;
然后徐福突然有冒出来,说是他有魔法,可以不用人力、财力就变出其中任意一条路出来;
秦始皇希望徐福能把要修的n-1条路中最长的那条变出来,但是徐福希望能把要求的人力数量最多的那条变出来;
对于每条路所需要的人力,是指这条路连接的两个城市的人数之和;
秦始皇给出了一个公式A/B,A是指要徐福用魔法变出的那条路所需人力,
B是指除了徐福变出来的那条之外的所有n-2条路径长度之和,选使得A/B值最大的那条;
分析:
为了使的A/B值最大,首先是需要是B尽量要小,所以可先求出n个城市的最小生成树;
然后就是决定要选择哪一条边用徐福的魔法来变;
可以枚举每一条边,假设最小生成树的值是Mst,而枚举的那条边长度是G[i][j],
如果这一条边已经是属于最小生成树上的,那么最终式子的值是A/(Mst-graph[i][j]);
如果这一条不属于最小生成树上的,那么添加上这条边,就会有n条边,那么就会使得有了一个环;
为了使得它还是一个生成树,就要删掉环上的一条边,为了让生成树的权值尽量小,那么就要删掉除了加入的那条边以外,权值最大的那条路径;
假设删除的那个边的权值是path[i][j],那么就是A/(Mst-path[i][j]);
解这题的关键也在于怎样求出次小生成树,具体实现时,更简单的方法是从每个节点i遍历整个最小生成树;
定义path[i][j]为从i到j的路径上最大边的权值,遍历图求出path[i][j]的值;
然后对于添加每条不在最小生成树中的边(i,j),新的生成树权值之和就是Mst+graph[i][j]–path[i][j],其最小值则为次小生成树;
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define max(a,b) ((a)>(b)?(a):(b)) const int INF=0x3fffffff; const int N=1005; struct Point { int x,y,p;//坐标,人口 void Get () { scanf("%d%d%d",&x,&y,&p); } double Dis (Point b) { return sqrt( 1.0*(x-b.x)*(x-b.x) + 1.0*(y-b.y)*(y-b.y) ); } }data ; int n,pre ; ////辅助数组,记录前驱 bool visit ; bool used ;//边是否在该MST中 double graph ,dist ; double path ;//从i到j的路径上最大边的权值 double Prim() { int i,j; double Mst=0; memset(visit,false,sizeof(visit)); memset(used,false,sizeof(used)); memset(path,0,sizeof(path)); visit[1]=true; for (i=1;i<=n;i++) { dist[i]=graph[1][i]; pre[i]=1; } for (i=1;i<n;i++) { int k=-1; for (j=1;j<=n;j++) if(visit[j]==false) if (k==-1 || dist[j]<dist[k]) k=j; used[k][pre[k]]=used[pre[k]][k] = true;//加入MST Mst+=graph[pre[k]][k]; visit[k]=true; for (j=1;j<=n;j++) { if (visit[j] && j!=k)//求从k到j的路径上最大边的权值 path[k][j]=path[j][k]=max(path[j][pre[k]], dist[k]); if (visit[j]==false && dist[j]>graph[k][j]) //更新相邻顶点的dis { dist[j]=graph[k][j]; pre[j]=k; } } } /* int ans=INF; //计算次小生成树 for (i=1;i<=n;i++) for (int j=1;j<=n;j++) if (i!=j && used[i][j]==false) ans=min(ans,Mst+graph[i][j]-path[i][j]);*/ return Mst; } int main () { int T,i,j; scanf("%d",&T); while (T--) { scanf("%d",&n); memset(graph,0,sizeof(graph)); for (i=1;i<=n;i++) data[i].Get(); for (i=1;i<=n;i++) for (j=i+1;j<=n;j++) graph[i][j]=graph[j][i]=data[i].Dis(data[j]); double Mst=Prim(); double ans=-1; for (i=1;i<=n;i++) for (j=i+1;j<=n;j++) { if (used[i][j]) ans=max(ans,(data[i].p+data[j].p)/(Mst-graph[i][j])); else ans=max(ans,(data[i].p+data[j].p)/(Mst-path[i][j])); } printf("%.2f\n",ans); } return 0; }
相关文章推荐
- AC自动机学习小记 Hdu 2222 Keywords Search (模板)
- 哈希表学习小记 Hdu 1280+1425+3785 (前m大数)(简单哈希)
- 线段树学习小记 Hdu 1754+Poj 3264 (区间最值)
- hdu 4081 次小生成树
- hdu 1232 变成生成树至少还要加几条边 (并查集模板题)
- hdu 4081 Qin Shi Huang's National Road System(次小生成树)
- hdu 4081 Qin Shi Huang's National Road System(次小生成树)
- BOOTSTRAP基础学习小记(一)简介模板、全局样式-web前端
- 拓扑排序学习小记 HDU 1285 确定比赛名次 + HDU 2647 Reward
- HDU 4081 Qin Shi Huang's National Road System (枚举次小生成树)
- HDU 4081 Excited!次小生成树与树状dp
- STL学习小记--与C++模板相关的几个特性
- 斯特林数 - 环排列 学习小记 Hdu 3625 Examining the Rooms + LightOJ 1326 Race
- 划分树学习小记 Poj 2104+Poj 2761+Hdu 2665 (区间第k大数)
- 扩展KMP算法(Extend KMP) 学习小记 Hdu 4333 Revolving Digits
- 数位dp学习小记 Hdu 3555
- 最长公共上升子序列(LCIS)学习小记 Hdu 1423 + Poj 2127 (LCIS路径输出)
- hdu 4081 Qin Shi Huang's National Road System(次小生成树变形)
- hdu 4081 Qin Shi Huang's National Road System(次小生成树)
- HDU - 4081 Qin Shi Huang's National Road System(次小生成树)