[kuangbin带你飞]专题八 生成树 - 次小生成树部分
百度了好多自学到了次小生成树 理解后其实也很简单
求最小生成树的办法目前遇到了两种
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带你飞]专题八 生成树 - 次小生成树部分的更多相关文章
- [ An Ac a Day ^_^ ][kuangbin带你飞]专题八 生成树 POJ 1679 The Unique MST
求最小生成树是否唯一 求一遍最小生成树再求一遍次小生成树 看看值是否相等就可以 #include<cstdio> #include<iostream> #include< ...
- [ An Ac a Day ^_^ ] [kuangbin带你飞]专题八 生成树 UVA 10600 ACM Contest and Blackout 最小生成树+次小生成树
题意就是求最小生成树和次小生成树 #include<cstdio> #include<iostream> #include<algorithm> #include& ...
- [kuangbin带你飞]专题1-23题目清单总结
[kuangbin带你飞]专题1-23 专题一 简单搜索 POJ 1321 棋盘问题POJ 2251 Dungeon MasterPOJ 3278 Catch That CowPOJ 3279 Fli ...
- 【算法系列学习三】[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 反向bfs打表和康拓展开
[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 这是一道经典的八数码问题.首先,简单介绍一下八数码问题: 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的 ...
- [kuangbin带你飞]专题十 匹配问题
A-L 二分匹配 M-O 二分图多重匹配 P-Q 二分图最大权匹配 R-S 一般图匹配带花树 模板请自己找 ID Origin Title 61 / 72 Problem A HD ...
- [kuangbin带你飞]专题十 匹配问题 一般图匹配
过去做的都是二分图匹配 即 同一个集合里的点 互相不联通 但是如果延伸到一般图上去 求一个一般图的最大匹配 就要用带花树来解决 带花树模板 用来处理一个无向图上的最大匹配 看了一会还是不懂 抄了一遍 ...
- [kuangbin带你飞]专题六 最小生成树
学习最小生成树已经有一段时间了 做一些比较简单的题还算得心应手..花了三天的时间做完了kuangbin的专题 写一个题解出来记录一下(虽然几乎都是模板题) 做完的感想:有很多地方都要注意 n == 1 ...
- [kuangbin带你飞]专题十五 数位DP
ID Origin Title 62 / 175 Problem A CodeForces 55D Beautiful numbers 30 / 84 Problem B HD ...
- [kuangbin带你飞]专题一 简单搜索 题解报告
又重头开始刷kuangbin,有些题用了和以前不一样的思路解决.全部题解如下 点击每道题的标题即可跳转至VJ题目页面. A-棋盘问题 棋子不能摆在相同行和相同列,所以我们可以依此枚举每一行,然后标记每 ...
随机推荐
- 修剪花卉(codevs 1794)
题目描述 Description ZZ对数学饱有兴趣,并且是个勤奋好学的学生,总是在课后留在教室向老师请教一些问题. 一天他早晨骑车去上课,路上见到一个老伯正在修剪花花草草,顿时想到了一个有关修剪花卉 ...
- 第一章 用记事本搭建C#程序
1.新建记事本:using System;class Text{ Console.WriteLine("你好如鹏网"); Console.WriteLine("www.r ...
- redhat6.2下的ssh密钥免密码登录(原创)
这个是我自己写的,鼓励转载,请说明转载地址:http://www.cnblogs.com/nucdy/p/5664840.html 在进行hadoop的免密码的登录操作是,老是发生no route等错 ...
- 调试工具GDB详解
1 简介 2 生成调试信息 3 启动GDB 的方法 4 程序运行上下文 4.1 程序运行参数 4.2 工作目录 4.3 程序的输入输出 5 设置断点 5.1 简单断点 5.2 多文件设置断点 5.3 ...
- C++ Primer与c++编程思想的比较(转)
C++primer是最经典的c++教材之一,它的经典程度要超过thinking in c++.连thinking in c++作者本人都说他写这本书在某种程度上是让读者更好的理解C++primer.但 ...
- Hadoop的mapreduce开发过程,我遇到的错误集锦(持续更新)
1.Text包导错了. 将import com.sun.jersey.core.impl.provider.entity.XMLJAXBElementProvider.Text; 改为import o ...
- 【HTML5】Video + DOM
效果图: <!DOCTYPE html> <html> <body> <div style="text-align:center;"> ...
- 中文在unicode中的编码范围
以前写过一篇贴子是写中文在unicode中的编码范围 unicode中文范围,但写的不是很详细,今天再次研究了下unicode,并给出详细的unicode取值范围. 本次研究的unicode对象是un ...
- python reduce()函数
reduce()函数 reduce()函数也是Python内置的一个高阶函数.reduce()函数接收的参数和 map()类似,一个函数 f,一个list,但行为和 map()不同,reduce()传 ...
- 模拟 POJ 2993 Emag eht htiw Em Pleh
题目地址:http://poj.org/problem?id=2993 /* 题意:与POJ2996完全相反 模拟题 + 字符串处理:无算法,读入两行字符串找出相应点用used标记,输出时标记过的输出 ...