将1号点从图中去掉过后,图会形成几个连通块,那么我们首先可以在这些连通块内部求最小生成树。

假设有\(tot\)个连通块,那么我们会从1号点至少选\(tot\)个出边,使得图连通。这时我们贪心地选择最小的,这应该都很好懂。

因为题目中的要求是度数不超过\(s\),那么也就是说我们可以从1号点出发,再加入\(s-tot\)条边,因为可能这些边的边权比连通块中的某些边边权小,那么替换过后答案肯定最优。

具体替换方法为:如果当前顶点度数为\(k\),我们现在要向\(k+1\)的度数扩展,我们肯定要枚举所有没用到过的出边,因为只会添加一条边,那么就会形成一个环。单独考虑一条边\((1,x)\),肯定会选择将\(1\)到\(x\)路径上面边权最大的边给替换掉。那么我们可以枚举所有的情况,最后取min,就能得到\(k+1\)度的最优解。最后一次类推就行了。。。。如果向\(k+1\)度扩展得不到更优解时,直接break掉就行了。

具体思路就是这样。。。。但是代码细节稍微有点多。

因为求最小生成树时会利用到边的信息,以及最后会考虑1的每个出边,所以我先把边给标号,并且用了一个\(v[i]\)来保存\(i\)号结点所有的出边,这样就会方便一些。

细节见代码吧:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <map>
#include <vector>
using namespace std;
typedef long long ll;
const int N = 35;
int t;
int n, s;
struct Edge{
int u, v, w;
}e[N * N];
vector <int> v[N], vec;
bool vis[N], used[N * N], check[N * N];
int tot;
ll ans ;
void dfs(int x) {
vis[x] = 1;
for(auto i : v[x]) {
int to = e[i].v, u = e[i].u;
if(to == x) to = u ;
if(to != 1 && !check[i]) {
vec.push_back(i) ;
check[i] = 1;
}
if(!vis[to] && to != 1) dfs(to) ;
}
}
bool cmp(int a, int b) {
return e[a].w < e[b].w;
}
int f[N], d[N], ee[N];
int find(int x) {
return f[x] == x ? x : f[x] = find(f[x]) ;
}
int insert(int i) {
int x = e[i].u, y = e[i].v;
int fx = find(x), fy = find(y) ;
if(fx != fy) {
f[fx] = fy;
ans += e[i].w;
used[i] = 1;
return 1;
} else return 0;
}
void dfs2(int x) {
vis[x] = 1;
for(auto i : v[x]) {
int u = e[i].u, to = e[i].v;
if(to == x) to = u;
if(!vis[to] && used[i]) {
if(e[i].w > d[x]) {
d[to] = e[i].w;
ee[to] = i;
} else {
d[to] = d[x] ;
ee[to] = ee[x] ;
}
dfs2(to) ;
}
}
}
int main() {
cin >> t;
while(t--) {
ans = 0;
//处理输入
cin >> n;
for(int i = 1; i < N; i++) v[i].clear() ;
map <string ,int> mp;
memset(check, 0, sizeof(check)) ;
memset(used, 0, sizeof(used)) ;
mp["Park"] = 1;
int num = 1;
tot = 0;
string s1, s2;
for(int i = 1; i <= n; i++) {
int dis;
cin >> s1 >> s2 >> dis;
if(mp.find(s1) == mp.end()) mp[s1] = ++num;
if(mp.find(s2) == mp.end()) mp[s2] = ++num;
e[i] = Edge{mp[s1], mp[s2], dis} ;
v[mp[s1]].push_back(i) ;
v[mp[s2]].push_back(i) ;
}
cin >> s;
//在每个连通块内求最小生成树
for(int i = 1; i < N; i++) f[i] = i;
memset(vis, 0, sizeof(vis)) ;
for(int i = 2; i <= num; i++) {
if(!vis[i]) {
vec.clear() ;
tot++;
dfs(i);
sort(vec.begin(), vec.end(), cmp) ;
for(auto i : vec) insert(i) ;
}
}
//选出最小的边让树连通
vec.clear() ;
for(auto i : v[1]) vec.push_back(i) ;
sort(vec.begin(), vec.end(), cmp) ;
int l = vec.size(), k;
for(int i = 0; i < tot; i++) {
for(k = 0; k < l; k++) {
int ok = insert(vec[k]) ;
if(ok) break ;
}
}
//贪心换边
int cnt = s - tot;
while(cnt--) {
memset(d, 0, sizeof(d)) ;
memset(vis, 0, sizeof(vis)) ;
dfs2(1);
int mn = 0, f = -1;
for(int j = 0; j < l; j++) {
int i = vec[j] ;
if(used[i]) continue ;
int x = e[i].u, y = e[i].v, to;
if(x == 1) to = y;
else to = x;
if(e[i].w - d[to] < mn) {
mn = e[i].w - d[to] ;
f = i;
}
}
if(f == -1) break ;
int i = f ;
int x = e[i].u, y = e[i].v, to;
if(x == 1) to = y;
else to = x;
used[i] = 1;
used[ee[to]] = 0;
ans += mn;
}
cout << "Total miles driven: ";
cout << ans << '\n';
if(t) cout << '\n' ;
}
return 0;
}
/*
13
Park 1 9
Park 2 10
Park 3 10
Park 4 10
Park 5 10
Park 6 10
Park 7 10
1 2 11
1 4 13
2 3 12
4 5 14
5 6 14
6 7 13
6
*/

UVA1537 Picnic Planning(思维+最小生成树)的更多相关文章

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

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

  2. POJ1639 - Picnic Planning

    原题链接 Description 给出一张个点的无向边权图并钦定点,求使得点的度不超过的最小生成树. Solution 首先无视掉与相连的所有边,原图会变成若干互不连通的个块.对每个块分别求MST,再 ...

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

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

  4. POJ1639 Picnic Planning (限制入度最小生成树)

    节点1是有度数限制的,把节点1去掉,就会形成若干个连通块,在每个连通块内部求最小生成树(prim算法实现),并求出每个连通块与1相连的最短的边,这样形成了初始状态的生成树. 假设(1,x)这条边没在生 ...

  5. POJ-1639 Picnic Planning 度数限制最小生成树

    解法参考的论文:https://wenku.baidu.com/view/8abefb175f0e7cd1842536aa.html 觉得网上的代码好像都是用邻接矩阵来实现的,觉得可能数据量大了会比较 ...

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

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

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

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

  8. poj1639 Picnic Planning 最小度数限制生成树

    题意:若干个人开车要去park聚会,可是park能停的车是有限的,为k.所以这些人要通过先开车到其它人家中,停车,然后拼车去聚会.另外,车的容量是无限的,他们家停车位也是无限的. 求开车总行程最短. ...

  9. poj 1639 Picnic Planning 度限制mst

    https://vjudge.net/problem/POJ-1639 题意: 有一群人,他们要去某一个地方,每个车可以装无数个人,给出了n条路,包含的信息有路连接的地方,以及路的长度,路是双向的,但 ...

随机推荐

  1. ASP.NET Core 中间件Diagnostics使用 异常和错误信息

    ASP.NET Core 中间件(Middleware)Diagnostics使用.对于中间件的介绍可以查看之前的文章ASP.NET Core 开发-中间件(Middleware). Diagnost ...

  2. Appium java-client库更新到6.x ,TouchAction类中弃用的函数及替代方法

    新版本的java-client已经取消swipe方法,很多TouchAction类中的很多老方法也都已经弃用,具体可以参考这边的官方说明文档: https://static.javadoc.io/io ...

  3. 一文看懂JS继承

    继承是OOP中大家最喜欢谈论的内容之一,一般来说,继承都两种方式:接口继承和实现继承而JavaScript中没有接口继承需要的方法,因此只能依靠实现继承.在讲继承的实现之前,我们首先来回顾一下什么是继 ...

  4. PostgreSQL 参数调整(性能优化)

    昨天分别在外网和无外网环境下安装PostgreSQL,有外网环境下安装的相当顺利.但是在无外网环境下就是两个不同的概念了,可谓十有八折.感兴趣的同学可以搭建一下. PostgreSQL安装完成后第一件 ...

  5. poj1458公共子序列 C语言

    /*Common SubsequenceTime Limit: 1000MS Memory Limit: 10000KTotal Submissions: 56416 Accepted: 23516D ...

  6. Delphi文字转语音TTS【支持选择语音库,播放,暂停,开始,停止,生成语音文件,设置音量,设置语速】

    作者QQ:(648437169) 点击下载➨文字转语音TTS [Delphi 文字转语音TTS]调用系统自带的TTS组件,支持XP,vista,win7,win8,win10系统,支持选择语音库,播放 ...

  7. 大数据之路【第十四篇】:数据挖掘--推荐算法(Mahout工具)

    数据挖掘---推荐算法(Mahout工具) 一.简介 Apache顶级项目(2010.4) Hadoop上的开源机器学习库 可伸缩扩展的 Java库 推荐引擎(协同过滤).聚类和分类 二.机器学习介绍 ...

  8. Mac Mini(late 2014) 添加NVMe固态组Fusion Drive

    我买的是Mac Mini(late 2014)中配,内置5400转1T机械硬盘,该配置即使到了2019年安装macOS Mojave系统依旧是够用的,但硬盘严重拖累了运行的速度.之前考虑到更换内置sa ...

  9. 处女篇:自用C#后端SqlHelper.cs类

    自用SqlHelper.cs类,此类来自软谋教育徐老师课程SqlHelper.cs! using System; using System.Collections; using System.Coll ...

  10. Scala 系列(一)—— Scala 简介及开发环境配置

    一.Scala简介 1.1 概念 Scala 全称为 Scalable Language,即"可伸缩的语言",之所以这样命名,是因为它的设计目标是希望伴随着用户的需求一起成长.Sc ...