解题报告

 

题意理解

给定一张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 ;
}

最新文章

  1. 日常工作bug总结
  2. 寿司点餐系统Sprint1总结
  3. CheckedListBoxControl 实现复选框的单选与多选功能
  4. Android 环境搭建
  5. 让复杂Json数据和对象自由转换 --- Gson
  6. 兼容所有浏览器的设为首页收藏本站js代码
  7. STL迭代器笔记
  8. 凌乱的yyy
  9. 数据仓库分层ODS DW DM 主题 标签
  10. leetcode20
  11. 了解java中垃圾回收机制
  12. 【git之】fetch和 pull的区别
  13. Iptables之recent模块小结
  14. ADO.NET 【实体类】【数据访问类】
  15. jms异步转同步调用实例
  16. 使用 urllib 解析 URL 链接
  17. [lr &amp; ps] 色彩空间管理
  18. Qt5_vs2013_error_C2001: 常量中有换行符__ZC
  19. 静态类和静态方法,抽象类和抽象方法,new关键字,值类型和引用类型,接口
  20. 点滴积累【other】---HTTP Error 503. The service is unavailable (转载)

热门文章

  1. confluence部署
  2. Spring boot之使用freemarker
  3. java 判断Map集合中包含指定的键名,则返回true,否则返回false。
  4. 自动化部署脚本--linux执行sh脚本
  5. spark 笔记 16: BlockManager
  6. spark 笔记 3:Delay Scheduling: A Simple Technique for Achieving Locality and Fairness in Cluster Scheduling
  7. kolla-ansible-----cinder存储配置
  8. 网易云课堂_C++程序设计入门(下)_第10单元:月映千江未减明 – 模板_第10单元 - 单元作业:OJ编程 - 创建数组类模板
  9. Spring----EJB
  10. 采用WPF技术开发截图程序