解题报告

 

题意理解

给定一张N个点,M个边的无向图,求出无向图的一颗最小生成树,但是我们要求一号节点的入度不可以超过给定的整数S

也就是一个最小生成树,要求它的一号节点,最多只能和S个节点相连.

 

思路确定

题意就已经告诉我们,我们的必备算法必然是最小生成树.但是具体的算法流程,我们还得思考一下.

首先,我们要知道两个性质.

  1. 一个最小生成树,它的任意一棵子树都是最小生成树.

  2. 也就是一个最小生成树,实际上是由很多棵最小生成树构成的.

根据上面所言的性质,我们可以这么考虑这道题目.


首先我们不妨不去考虑这个有特殊限制的一号节点,那么我们忽略掉这个一号节点后.

原图变成了T个连通块.

设T表示为抛去第一号节点后有T个连通块设T表示为抛去第一号节点后有T个连通块

那么我们对于每一个连通块,都可以在这个连通块内部求出它的最小生成树.


我们接下来再来考虑,如何让这些连通块与我们的一号节点相连,构成我们题目的最小生成树.

首先我们很容易求出一个相对较小的生成树.切记不是最小生成树

对于每一个连通块而言,显然要在每一个连通块之中选出一个节点与我们的一号节点的权值最小.即(1,p)的权值要尽量小.

p∈每一个单独的连通块

那么此时,我们发现我们成功将节点们连接在一起了,构成了一个最小生成树,那么现在的问题就是,如何优化我们的生成树,将其变成我们的最小生成树.

我们现在知道和一号节点连接的点,一共有T个,但是题目中要求不多于S个节点就好了.

分类讨论一下

若S<T

那么我们必然就是无解情况.

若S=T

那么此时我们的生成树,就是我们的最小生成树.

若S>T

我们发现,对于一个节点而言,它不一定要属于自己原本的连通块,它可以和节点11相连

我们可以考虑无向图从节点11出发的每条边(1,x,z),其中边权为zz,那么假如说(1,x)这条边,它不在当前的生成树内.

那么我们就可以找到从当前生成树总(1,x)这条路径上的权值最大边(u,v,w)将它删除.

如果说我添加(1,x,z)这条边,我就可以删除(u,v,w)这条边.

然后我们这颗生成树的权值就可以减少w−z

综上所述,我们每一次从每一个连通块里面找,找到让w−z的值最大的点,然后添加(1,x,z),删除(u,v,w)

直到

T==S或者w−z≤0

也就是不可以加边,或者加边已经木有意义了.

具体参见 汪汀2004年的国家集训队论文,讲的很详细。

#include <bits/stdc++.h>
using namespace std;
const int N=;
#define quick() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)//读入优化
#define mem(a,b) memset(a,b,sizeof(a))//初始化
#define init() mem(g,0),mem(vis,false),root=cnt=tot2=tot=0,q.clear(),q2.clear()//初始化大军
#define add(a,b,c) g[a][b]=g[b][a]=c//无向图加边
#define mk(a,b) make_pair(a,b)//简便
int tot2,tot,n,m,fa[N],cnt,c,s,root,g[][],dis[][];
//tot2为边的数量
//tot为点的数量
//cnt为编号的数量
map<string,int> q;//映射关系
map<pair<int,int>,bool> q2;//统计这条边是否出现在最小生成树中
int vis[N];//标记连通块的编号
string a,b;
int find(int x)
{
return x==fa[x]?fa[x]:fa[x]=find(fa[x]);//并查集找红太阳
}
struct edge1
{
int x,y,w;
} g2[N];
int cmp (edge1 a,edge1 b)
{
return a.w<b.w;//最小边排序
}
struct node
{
int u,v,d;//(u,v)节点权值为d
inline void inits()
{
u=v=;
d=-;
}
} dp[N];
struct edge2
{
inline void add_edge(int a,int b,int c)//加入一条边
{
g2[++tot2].x=a;//起点
g2[tot2].y=b;//终点
g2[tot2].w=c;//权值
}
inline int kruskal()
{
sort(g2+,g2++tot2,cmp);//排序,找最小
int ans=;//我们的目标连通块的连通块编号
for(int i=; i<=tot2; i++)
{
int x=find(g2[i].x),y=find(g2[i].y);//求出所在连通块
if (x== || y== || x==y)//不是目标连通块,或者已经在一起了
continue;
fa[x]=y;//合并
ans+=g2[i].w;//统计
q2[mk(g2[i].x,g2[i].y)]=true;//这条边出现过
q2[mk(g2[i].y,g2[i].x)]=true;
}
return ans;
}
} g3;
void read()
{
quick();
init();
cin>>n;
root=q["Park"]=tot=;//Park节点就是我们的一号节点
for(int i=; i<=n; i++)
{
cin>>a>>b>>c;
if (!q[a])//名字读入
q[a]=(++tot);//新编号
if (!q[b])
q[b]=(++tot);//新编号
g3.add_edge(q[a],q[b],c);//加边
add(q[a],q[b],c);//加边
fa[i]=i;//初始化每个点的父亲节点
}
cin>>s;
}
void dfs(int x)
{
for(int j=; j<=tot; j++)
if (g[x][j] && !vis[j])//有边,但是木有被标记
{
vis[j]=cnt;
dfs(j);
}
}
void pd()//连通块划分
{
for(int i=; i<=tot; i++)
if (!vis[i])
{
cnt++;//又来一个
vis[i]=cnt;
dfs(i);
}
}
void dfs(int now,int last)//计算(1,x)路径上最大边
{
for(int i=; i<=tot; i++)
{
if(i==last || !q2[mk(now,i)])//点重叠,或者没有这条边
continue;
if(dp[i].d==-)//没有来过
{
if(dp[now].d>g[now][i])
dp[i]=dp[now];
else
{
dp[i].u=now;
dp[i].v=i;
dp[i].d=g[now][i];
}
}
dfs(i,now);
}
}
void work()
{
pd();
int ans=g3.kruskal();//统计每一个连通块的值
for(int i=; i<=cnt; i++)
{
int now=0x3f3f3f3f,st=;//初始值为INF
for(int j=; j<=tot; j++)
if (vis[j]==i)//属于这个连通块
if (now>g[][j] && g[][j]!=)
{
now=g[][j];//找到与1相连最小的边
st=j;
}
ans+=now;//将每一个连通块与1相连
q2[mk(,st)]=q2[mk(st,)]=true;
}
int t=cnt;
while(s>t)
{
s--;
int now=,idx=;
for(int i=; i<=; i++)
dp[i].inits();
dfs(,-);//求每一个点到1的途中最大边是谁?
for(int j=; j<=tot; j++)
{
if(now<dp[j].d-g[][j] && g[][j])
{
now=dp[j].d-g[][j];//找到最大权值边
idx=j;
}
}
if (now<=)//已经不会多优秀了
break;
ans=ans-now;
q2[mk(dp[idx].u,dp[idx].v)]=false;//删除边
q2[mk(,idx)]=q2[mk(idx,)]=true;//添加边
}
cout<<"Total miles driven: "<<ans;
}
int main()
{
read();
work();
return ;
}

Picnic Planning POJ - 1639(度限制生成树)的更多相关文章

  1. Picnic Planning POJ - 1639(最小k度生成树)

    The Contortion Brothers are a famous set of circus clowns, known worldwide for their incredible abil ...

  2. poj1639 Picnic Planning,K度限制生成树

    题意: 矮人虽小却喜欢乘坐巨大的轿车,车大到能够装下不管多少矮人.某天,N(N≤20)个矮人打算到野外聚餐.为了集中到聚餐地点,矮人A 要么开车到矮人B 家中,留下自己的轿车在矮人B 家,然后乘坐B ...

  3. POJ 1639 Picnic Planning:最小度限制生成树

    题目链接:http://poj.org/problem?id=1639 题意: 给你一个无向图,n个节点,m条边,每条边有边权. 让你求一棵最小生成树,同时保证1号节点的度数<=k. 题解: 最 ...

  4. POJ 1639 Picnic Planning(最小度限制生成树)

    Description The Contortion Brothers are a famous set of circus clowns, known worldwide for their inc ...

  5. 【POJ 1639】 Picnic Planning (最小k度限制生成树)

    [题意] 有n个巨人要去Park聚会.巨人A和先到巨人B那里去,然后和巨人B一起去Park.B君是个土豪,他家的停车场很大,可以停很多车,但是Park的停车场是比较小.只能停k辆车.现在问你在这个限制 ...

  6. POJ 1639 Picnic Planning 最小k度生成树

    Picnic Planning Time Limit: 5000MS   Memory Limit: 10000K Total Submissions:11615   Accepted: 4172 D ...

  7. poj 1639 最小k度限制生成树

    题目链接:https://vjudge.net/problem 题意: 给各位看一下题意,算法详解看下面大佬博客吧,写的很好. 参考博客:最小k度限制生成树 - chty - 博客园  https:/ ...

  8. poj1639,uva1537,uvalive2099,scu1622,fzu1761 Picnic Planning (最小限制生成树)

    Picnic Planning Time Limit: 5000MS   Memory Limit: 10000K Total Submissions: 10742   Accepted: 3885 ...

  9. K度限制MST poj 1639

    /* k度限制MST:有一个点的度<=k的MST poj 1639 要求1号点的度不超过k 求MST 我们先把1号点扔掉 跑MST 假设有sum个连通分支 然后把这sum个分支连到1上 就得到了 ...

随机推荐

  1. Generalizing from a Few Examples: A Survey on Few-Shot Learning(从几个例子总结经验:少样本学习综述)

    摘要:人工智能在数据密集型应用中取得了成功,但它缺乏从有限的示例中学习的能力.为了解决这一问题,提出了少镜头学习(FSL).利用先验知识,可以快速地从有限监督经验的新任务中归纳出来.为了全面了解FSL ...

  2. 论文阅读:ClickNF: a Modular Stack for Custom Network Functions

    摘要: 网络功能虚拟化最近允许用等效的软件实现代替专用设备, Click路由器是朝这个方向迈出的第一步,它定义了用于通用数据包处理的模块化平台. 尽管Click具有重大影响,但它不提供本机L4实现,而 ...

  3. Python3学习笔记(十三):装饰器

    装饰器就是一个闭包,它的主要作用是在不改变原函数的基础上对原函数功能进行扩展. 我们先来写一个简单的函数: from time import sleep def foo(): print(" ...

  4. JIRA7.13版本创建项目:字段和界面(三)

    这是我从网上找的资料和最新版的相差不大,可以借鉴原文链接:http://ju.outofmemory.cn/entry/367224 项目的版本号取决于修复版本,不是影响版本 字段 我们已经知道如何在 ...

  5. python学习之路(9)

    函数的参数 定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了.对于函数的调用者来说,只需要知道如何传递正确的参数,以及函数将返回什么样的值就够了,函数内部的复杂逻辑被封装起来,调 ...

  6. SQL中模糊查询的模式匹配

    SQL模糊查询的语法为: “Select column FROM table Where column LIKE 'pattern'”. SQL提供了四种匹配模式: 1. % 表示任意0个或多个字符. ...

  7. 理解PyTorch的自动微分机制

    参考Getting Started with PyTorch Part 1: Understanding how Automatic Differentiation works 非常好的文章,讲解的非 ...

  8. C++入门经典-例5.15-回收动态内存的一般处理步骤

    1:正确的步骤应该是如下代码所示: // 5.15.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostrea ...

  9. 2018-2019-2 网络对抗技术 20165232 Exp7 网络欺诈防范

    2018-2019-2 网络对抗技术 20165232 Exp7 网络欺诈防范 原理与实践说明 1.实践目标 理解常用网络欺诈背后的原理,以提高防范意识,并提出具体防范方法. 2.实践内容概述 简单应 ...

  10. Laravel框架之获取URL地址

    1. 使用 Request 类: $url = Request::getRequestUri(); 2. 使用 $request 对象: public function show(Request $r ...