百度了好多自学到了次小生成树 理解后其实也很简单

求最小生成树的办法目前遇到了两种

1 prim 记录下两点之间连线中的最长段 F[i][k] 之后枚举两点 若两点之间存在没有在最小生成树中的边 那么尝试加入它 然后为了不成环 要在环中去除一条边 为了达到"次小"的效果 减去最长的 即F[i][k] 求一下此时的数值 不断更新次小值

2 kru 记录下被加入到最小生成树中的线段 然后进行n-1次枚举 每次都跳过一条被记录的边 求一次kru 得到的值为-1或者一个可能成为次小的值 不断更新 判断有无次小生成树 得到次小值

poj 1679 求一个图中是否存在唯一的最小生成树 在最小生成树的专题中采用的办法是在加入最后一条可行边的时候看相同权值的边有没有另外的选择 如果有 就不唯一 如果使用次小生成树的办法来解 可以求一次次小生成树 如果次小值=最小值 不唯一 反之则反

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<math.h>
#include<queue>
#include<iostream>
using namespace std;
#define MAXN 105
#define MAXM 10050
int dis[MAXN];
int ta[MAXN][MAXN];
int pre[MAXN];
bool use[MAXN][MAXN];
bool vis[MAXN];
int F[MAXN][MAXN];
int ans1,ans2;
int n,m;
int prim(){
int ans=0;
vis[1]=false;
for(int i=1;i<=n;i++)pre[i]=1;
pre[1]=-1;
for(int i=2;i<=n;i++)
{
int minn=999999999;
int p=-1;
for(int k=2;k<=n;k++)
{
if(vis[k]&&dis[k]<minn)
{
p=k;
minn=dis[k];
}
}
if(minn==999999999)
return -1;
vis[p]=false;
ans+=dis[p];
use[p][pre[p]]=use[pre[p]][p]=false;
for(int k=1;k<=n;k++)
{
if(!vis[k])
F[p][k]=F[k][p]=max(dis[p],F[k][pre[p]]); /// dis[p] 当前树到p点的距离 F[k][pre[p]] k点到曾直接松弛过p点的点的uli[略雾]
if(vis[k])
{
if(dis[k]>ta[p][k])
{
dis[k]=ta[p][k];
pre[k]=p;
}
}
}
}
return ans;
}
int second()
{
int ans=999999999;
for(int i=1;i<=n;i++)
for(int k=i+1;k<=n;k++)
{
if(use[i][k])
if(ans>ans1-F[i][k]+ta[i][k])
ans=ans1-F[i][k]+ta[i][k];
}
return ans;
}
int main(){
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
memset(use,false,sizeof(use));
for(int i=1;i<=n;i++)
for(int k=1;k<=n;k++)
ta[i][k]=999999999;
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
ta[u][v]=ta[v][u]=w;
use[u][v]=use[v][u]=true; }
for(int i=2;i<=n;i++)
dis[i]=ta[1][i];
dis[1]=0;
memset(vis,true,sizeof(vis));
memset(F,0,sizeof(F));
ans1=prim();
ans2=second();
if(ans1==ans2)
printf("Not Unique!\n");
else printf("%d\n",ans1);
}
}

hdu 4081 题意简直...秦始皇想让n个郡县都可以相互到达 又想让道路尽可能的短 徐福说他可以让一条路刷的一下建成 不耗费人力(所耗人力等于道路两端郡县的人数) 然后两人分歧 最后决定弄出来一个折中的办法 B为除了徐福建造的路的所有路的长度 A为徐福建造的路省下的人力 使A/B最大 求最大值

我们求出最小生成树 如果徐福建造的路在最小生成树中 枚举这些路 更新比值

如果徐福建造的路不在呢?次小生成树的思想 加入徐福建造的路 然后减去F[i][k] 更新比值

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<math.h>
using namespace std;
int tot;
double ans;
struct node
{
double x,y,p;
};
node point[1050];
int n;
double disz(int p1,int p2)
{
return sqrt((point[p1].x-point[p2].x)*(point[p1].x-point[p2].x)+(point[p1].y-point[p2].y)*(point[p1].y-point[p2].y));
}
double dis[1050];
double cost[1050][1050];
int pre[1050];
bool use[1050][1050];
double F[1050][1050];
bool vis[1050];
double prim()
{
double res=0;
memset(vis,true,sizeof(vis));
vis[1]=false;
for(int i=2;i<=n;i++)pre[i]=1;
pre[1]=0;
for(int i=1;i<=n-1;i++)
{
int p=-1;
double minn=9999999999;
for(int k=1;k<=n;k++)
{
if(vis[k])
if(dis[k]<minn)
{
p=k;
minn=dis[k];
}
}
if(p==-1)
return -1;
vis[p]=false;
res+=dis[p];
use[p][pre[p]]=use[pre[p]][p]=true;
for(int k=1;k<=n;k++)
{
if(!vis[k]&&p!=k)
F[p][k]=F[k][p]=max(dis[p],F[k][pre[p]]);
if(vis[k])
if(dis[k]>cost[p][k])
{
dis[k]=cost[p][k];
pre[k]=p;
}
}
}
return res;
}
int main(){
int t;
scanf("%d",&t);
while(t--)
{
tot=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lf%lf%lf",&point[i].x,&point[i].y,&point[i].p);
for(int i=1;i<=n;i++)
for(int k=i;k<=n;k++)
{
cost[k][i]=cost[i][k]=disz(i,k);
}
for(int i=2;i<=n;i++)
dis[i]=cost[1][i];
dis[1]=0;
memset(F,0,sizeof(F));
memset(use,false,sizeof(use));
double ans=prim();
///枚举边
double pri=0;
for(int i=1;i<=n;i++)
{
for(int k=i+1;k<=n;k++)
{
if(use[i][k])
{
double peo=(point[i].p+point[k].p);
double w = cost[i][k];
double ww=ans-w;
double bz=peo/ww;
if(bz>pri)
pri=bz;
}
else
{
double peo=(point[i].p+point[k].p);
double w = ans-F[i][k];
double bz=peo/w;
if(bz>pri)
pri=bz;
}
}
}
printf("%.2f\n",pri);
}
}

uva 10600 题意就是让求最小生成树值和次小生成树值

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<math.h>
using namespace std;
int n;
int m;
int ans1,ans2;
int cost[105][105];
int dis[105];
bool vis[105];
int F[105][105];
bool use[105][105];
int pre[105];
int prim()
{
memset(vis,true,sizeof(vis));
for(int i=1;i<=n;i++)pre[i]=1;
memset(F,0,sizeof(F));
vis[1]=false;
int res=0;
for(int i=1;i<=n-1;i++)
{
int p=-1;
int minn=999999999;
for(int j=1;j<=n;j++)
{
if(vis[j])
{
if(minn>dis[j])
{
minn=dis[j];
p=j;
}
}
}
if(minn==999999999)
return -1;
vis[p]=false;
res+=minn;
use[p][pre[p]]=use[pre[p]][p]=false;
for(int j=1;j<=n;j++)
{
if(!vis[j]&&j!=p)F[j][p]=F[p][j]=max(F[j][pre[p]],dis[p]); ///因为没有加j!=p 强行wa了几次
if(vis[j]&&dis[j]>cost[j][p])
{
dis[j]=cost[j][p];
pre[j]=p;
}
}
}
return res;
}
void second()
{
ans2=999999999;
for(int i=1;i<=n;i++)
{
for(int k=1;k<=n;k++)
{
if(i!=k&&use[i][k]==true&&pre[i]!=k&&pre[k]!=i)
{
if(ans2>ans1-F[i][k]+cost[i][k])
{
ans2=ans1-F[i][k]+cost[i][k];
}
}
}
}
return ; }
int main(){
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int k=1;k<=n;k++)
{
if(i==k)
cost[i][k]=0;
else cost[i][k]=999999999;
}
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
cost[u][v]=cost[v][u]=min(w,cost[u][v]);
use[u][v]=use[v][u]=true;
}
dis[1]=0;
for(int i=2;i<=n;i++)
dis[i]=cost[1][i];
ans1=prim();
second();
printf("%d %d\n",ans1,ans2);
}
}

uva 10462 一个图中有没有最小生成树和次小生成树 输出回答或次小值

难点在于 两个点之间的边并不唯一 在这里想到了用kru来计算最小生成树 即开头提到的第二种办法

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
using namespace std;
int n,m;
struct node
{
int u,v,w;
};
int fa[105];
node a[205];
void init(){
for(int i=1;i<=n;i++)fa[i]=i;
}
int find(int x)
{
if(fa[x]==x)
return x;
return fa[x]=find(fa[x]);
}
void un(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx==fy)
return ;
fa[fx]=fy;
return ;
}
int cmp(node a,node b)
{
return a.w<b.w;
}
int gc[205];
int tot;
int kru(){
tot=0;
init();
int res=0;
int cnt=0;
if(cnt==n-1)
return res;
for(int i=0;i<m;i++)
{
int u=a[i].u;
int v=a[i].v;
int w=a[i].w;
if(find(u)!=find(v))
{
gc[tot++]=i;
un(u,v);
cnt++;
res+=w;
}
if(cnt==n-1)
return res;
}
return -1;
}
int kru2(int e)
{
init();
int cnt=0;
int res=0;
if(cnt==n-1)
return res;
for(int i=0;i<m;i++)
{
int u=a[i].u;
int v=a[i].v;
int w=a[i].w;
if(i==gc[e])
continue;
if(find(u)!=find(v))
{
un(u,v);
cnt++;
res+=w;
}
if(cnt==n-1)
return res;
}
return -1;
}
int main(){
int t;
int tt=0;
scanf("%d",&t);
while(t--)
{
tt++;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
a[i].u=u;
a[i].v=v;
a[i].w=w;
}
sort(a,a+m,cmp);
int ans1,ans2;
ans1=kru();
printf("Case #%d : ",tt);
if(ans1==-1)
printf("No way\n");
else
{
ans2=999999999;
bool cunzai=false;
for(int i=0;i<tot;i++)
{
int ans3=kru2(i);
if(ans3!=-1)
{
cunzai=true;
ans2=min(ans2,ans3);
}
}
if(!cunzai)
printf("No second way\n");
else printf("%d\n",ans2);
}
/*for(int i=0;i<tot;i++)
printf("%d\n",gc[i]);*/
//printf("%d\n",ans1);
}
}

  

[kuangbin带你飞]专题八 生成树 - 次小生成树部分的更多相关文章

  1. [ An Ac a Day ^_^ ][kuangbin带你飞]专题八 生成树 POJ 1679 The Unique MST

    求最小生成树是否唯一 求一遍最小生成树再求一遍次小生成树 看看值是否相等就可以 #include<cstdio> #include<iostream> #include< ...

  2. [ An Ac a Day ^_^ ] [kuangbin带你飞]专题八 生成树 UVA 10600 ACM Contest and Blackout 最小生成树+次小生成树

    题意就是求最小生成树和次小生成树 #include<cstdio> #include<iostream> #include<algorithm> #include& ...

  3. [kuangbin带你飞]专题1-23题目清单总结

    [kuangbin带你飞]专题1-23 专题一 简单搜索 POJ 1321 棋盘问题POJ 2251 Dungeon MasterPOJ 3278 Catch That CowPOJ 3279 Fli ...

  4. 【算法系列学习三】[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 反向bfs打表和康拓展开

    [kuangbin带你飞]专题二 搜索进阶 之 A-Eight 这是一道经典的八数码问题.首先,简单介绍一下八数码问题: 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的 ...

  5. [kuangbin带你飞]专题十 匹配问题

        A-L 二分匹配 M-O 二分图多重匹配 P-Q 二分图最大权匹配 R-S 一般图匹配带花树 模板请自己找     ID Origin Title   61 / 72 Problem A HD ...

  6. [kuangbin带你飞]专题十 匹配问题 一般图匹配

    过去做的都是二分图匹配 即 同一个集合里的点 互相不联通 但是如果延伸到一般图上去 求一个一般图的最大匹配 就要用带花树来解决 带花树模板 用来处理一个无向图上的最大匹配 看了一会还是不懂  抄了一遍 ...

  7. [kuangbin带你飞]专题六 最小生成树

    学习最小生成树已经有一段时间了 做一些比较简单的题还算得心应手..花了三天的时间做完了kuangbin的专题 写一个题解出来记录一下(虽然几乎都是模板题) 做完的感想:有很多地方都要注意 n == 1 ...

  8. [kuangbin带你飞]专题十五 数位DP

            ID Origin Title   62 / 175 Problem A CodeForces 55D Beautiful numbers   30 / 84 Problem B HD ...

  9. [kuangbin带你飞]专题一 简单搜索 题解报告

    又重头开始刷kuangbin,有些题用了和以前不一样的思路解决.全部题解如下 点击每道题的标题即可跳转至VJ题目页面. A-棋盘问题 棋子不能摆在相同行和相同列,所以我们可以依此枚举每一行,然后标记每 ...

随机推荐

  1. Floyd最短路算法

    Floyd最短路算法 ----转自啊哈磊[坐在马桶上看算法]算法6:只有五行的Floyd最短路算法 暑假,小哼准备去一些城市旅游.有些城市之间有公路,有些城市之间则没有,如下图.为了节省经费以及方便计 ...

  2. Linux Top

    http://www.it165.net/os/html/201402/7262.html

  3. 设计模式学习之抽象工厂(Abstract Factory,创建型模式)(3)

    假如我们的苹果和香蕉还分为北方的和南方的,那么苹果Apple和香蕉Banana就是抽象类了,所以采集的方法就应该抽象的 第一步: 我们会创建北方的苹果NorthApple类和SourthBanana类 ...

  4. hdu 1728:逃离迷宫(DFS,剪枝)

    逃离迷宫 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  5. poj 3281 最大流+建图

    很巧妙的思想 转自:http://www.cnblogs.com/kuangbin/archive/2012/08/21/2649850.html 本题能够想到用最大流做,那真的是太绝了.建模的方法很 ...

  6. hdu 1542 扫描线求矩形面积的并

    很久没做线段树了 求矩形面积的并分析:1.矩形比较多,坐标也很大,所以横坐标需要离散化(纵坐标不需要),熟悉离散化后这个步骤不难,所以这里不详细讲解了,不明白的还请百度2.重点:扫描线法:假想有一条扫 ...

  7. c++find函数用法

    头文件 #include <algorithm> 函数实现 template<class InputIterator, class T> InputIterator find ...

  8. Mongoose Schemas中定义日期以及timestamps选项的妙用

    本文转自:http://www.cnblogs.com/jaxu/p/5595451.html 在Node.js中使用MongoDB少不了Mongoose.假设有如下Mongoose Schemas的 ...

  9. Ajax 学习之创建XMLHttpRequest对象------Ajax的核心

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  10. mysql之对触发器的操作

    1. 为什么要使用触发器? 触发器与函数有些类似,都需要声明,执行.但是触发器的执行不是由程序调用,也不是由手工启动,而是由事件来触发,激活,从而实现执行. 当触发DELETE,INSERT,UPDA ...