解题报告

 

题意理解

给定一张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. Selenium 对元素的判断(expected_conditions)(转载)

    我们在用webdriver去操作元素时,先要判断这个元素是否存在,存在才去操作,否则就会报错. selenium的expected_conditions模块提供了一些判断方法 场景 Expected ...

  2. 「WC 2007」剪刀石头布

    题目链接 戳我 \(Solution\) 直接求很明显不太好求,于是考虑不构成剪刀石头布的情况. 我们现在假设一个人\(i\)赢了\(x\)场,那么就会有\(\frac{x*(x-1)}{2}\) 我 ...

  3. Eclipse常用快捷键与IDEA中的对比.

    最近从github下载了一些项目,但是看了一下使用的编译器是IDEA的,所以就下载了一个IDEA. 这边可以提供几个网址:只要是针对各个下载idea之后的一些激活相关的帮助. http://idea. ...

  4. 套接字之recvmsg系统调用

    recvmsg系统调用允许用户指定msghdr结构来接收数据,可以将数据接收到多个缓冲区中,并且可以接收控制信息:接收信息过程与其他接收系统调用核心一致,都是调用传输层的接收函数进行数据接收: SYS ...

  5. 第六周学习总结&java实验报告四

    第六周学习总结&java实验报告四 学习总结: 上一周因为接近国庆假期,所以老师没有讲太多的新知识点,只要是带我们一起做了一个动物模拟变声器的实验,进一步了解和学习到继承的 有关知识点和应用: ...

  6. 详讲KMP算法

    两个字符串: 模式串:ababcaba 文本串:ababcabcbababcabacaba KMP算法作用:快速在文本串中匹配到模式串 如果是穷举法的方式: 大家有发现,这样比效率很低的. 所以就需要 ...

  7. Note: Time clocks and the ordering of events in a distributed system

    http://research.microsoft.com/en-us/um/people/lamport/pubs/time-clocks.pdf 分布式系统的时钟同步是一个非常困难的问题,this ...

  8. 数组 Kotlin(5)

    数组 数组在 Kotlin 中使用 Array 类来表示,它定义了 get 和 set 函数(按照运算符重载约定这会转变为 [] ) 和 size 属性,以及一些其他有用的成员函数:基本类型 clas ...

  9. SAP MaxDB Backup and Restore

    Back up the data and redo log entries from the data and log areas of your database to data carriers ...

  10. [Java]分解算术表达式一

    源码: package com.hy; import java.io.BufferedReader; import java.io.IOException; import java.io.InputS ...