[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-棋盘问题 棋子不能摆在相同行和相同列,所以我们可以依此枚举每一行,然后标记每 ...
随机推荐
- Eclipse中android工程C++文件中出现的莫名其妙的错误
大多数是std库相关的问题,例如 vector<int> v; v.push_back(23);//这句语法是没有错误的,但是每次执行Run As的时候就会报错 尝试1:在工程名右键-Cl ...
- Doodle Poll 投票文档
使用Doodle Poll网页文件可以让大家投票看什么时间大家都合适.
- 仓鼠找sugar(洛谷 3398)
题目描述 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴是一个树形结构.这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c) ...
- Android实现高仿QQ附近的人搜索展示
本文主要实现了高仿QQ附近的人搜索展示,用到了自定义控件的方法 最终效果如下 1.下面展示列表我们可以使用ViewPager来实现(当然如果你不觉得麻烦,你也可以用HorizontalScrollVi ...
- Java Hour 10
有句名言,叫做10000小时成为某一个领域的专家.姑且不辩论这句话是否正确,让我们到达10000小时的时候再回头来看吧. 本文作者Java 现经验约为10 Hour,请各位不吝赐教. Hour 10 ...
- hdu 1755 数学 ***
链接:点我 题解可以看这里:点我和这里 #include<cstdio> #include<cstring> #include<algorithm> #define ...
- x264码率控制方法介绍
转自:http://www.bubuko.com/infodetail-471698.html 1. X264显式支持的一趟码率控制方法有:ABR, CQP, CRF. 缺省方法是CRF.这三种方式 ...
- IIS-如果外网访问不到 域名
如果访问不到 域名 , 可以 给域名的目录 增加“IIS_IUSERS”权限.
- 使用jQuery实现类似开关按钮的效果
转自:http://www.cnblogs.com/linjiqin/p/3148228.html 本案例实现类似开关按钮效果. 页面有下拉列表.文本框.按钮等表单元素,大致实现如下效果:1.页面一加 ...
- Bean的前身今世&处理器&Aware
出生: <bean>......</bean> 幼年:BeanDefinition bean的接口定义 小学:GenericBeanDefinition 基础的bean映射 ...