[题目链接]

http://poj.org/problem?id=1639

[算法]

首先,我们可以用深度优先遍历求出1号节点去除后有几个联通块

设共有T个联通块,若T > K则无解,否则 :

求出这些联通块的最小生成树,得到一棵最小T度生成树,我们尝试改动(K - T)条边,使得答案变得更小,具体过程如下 :

枚举所有与1相连的边,若这条边不在当前的生成树中,我们用广度优先搜索求出生成树上1号节点到该条边的节点中最长的边,用这条边的权值减去枚举边的权值即为生成树权值和变小了多少,求出这个变小的最大值

如果这个最大值大于0,将这个最大值对应的边从生成树中删除,并加入新的边,否则退出

重复以上过程(K - T)次,即可

[代码]

#include <algorithm>
#include <bitset>
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <limits>
#include <list>
#include <map>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <utility>
#include <vector>
#include <cwchar>
#include <cwctype>
#include <stack>
#include <limits.h>
using namespace std;
#define MAXN 1010
struct Edge
{
int u,v,w;
} e[MAXN],edge[MAXN][MAXN];
int i,j,n,w,k,tot,block,ans,mx;
int val[MAXN],size[MAXN],fa[MAXN],p[MAXN],belong[MAXN];
bool visited[MAXN],flag[MAXN];
int mst[MAXN][MAXN];
map<string,int> mp;
string u,v;
vector< int > a[MAXN];
pair<int,int> ps,new_e,tmp; inline bool cmp(Edge a,Edge b)
{
return a.w < b.w;
}
inline int get_root(int x)
{
if (fa[x] == x) return x;
return fa[x] = get_root(fa[x]);
}
inline void dfs(int u)
{
int i,v;
visited[u] = true;
belong[u] = block;
for (i = ; i < a[u].size(); i++)
{
v = a[u][i];
if (e[v].u == u && e[v].v != && !flag[v])
{
flag[v] = true;
edge[block][++size[block]] = e[v];
dfs(e[v].v);
} else if (e[v].v == u && e[v].u != && !flag[v])
{
flag[v] = true;
edge[block][++size[block]] = e[v];
dfs(e[v].u);
}
}
}
inline void kruskal(int id)
{
int i,su,sv;
static int s[MAXN];
for (i = ; i <= n; i++) fa[i] = i;
sort(edge[id] + ,edge[id] + size[id] + ,cmp);
for (i = ; i <= size[id]; i++)
{
su = get_root(edge[id][i].u);
sv = get_root(edge[id][i].v);
if (su != sv)
{
ans += edge[id][i].w;
mst[edge[id][i].u][edge[id][i].v] = edge[id][i].w;
mst[edge[id][i].v][edge[id][i].u] = edge[id][i].w;
fa[su] = sv;
}
}
}
inline pair<int,int> bfs(int s)
{
int i,cur,l,r,now,mx;
static bool visited[MAXN];
static pair<int,int> q[MAXN];
static int pre[MAXN];
bool found = false;
pair<int,int> res;
memset(visited,false,sizeof(visited));
q[l = r = ] = make_pair(s,);
visited[s] = true;
pre[] = -;
while (l <= r)
{
cur = q[l].first;
for (i = ; i <= n; i++)
{
if (visited[i]) continue;
if (!mst[cur][i]) continue;
visited[i] = true;
q[++r] = make_pair(i,mst[cur][i]);
pre[r] = l;
if (i == )
{
found = true;
break;
}
}
if (found) break;
l++;
}
if (!found) return make_pair(,);
now = r; mx = ;
while (pre[now] != -)
{
if (q[now].second > mx)
{
mx = q[now].second;
res = make_pair(q[pre[now]].first,q[now].first);
}
now = pre[now];
}
return res;
}
int main()
{

     cin.tie(0);
cin >> n;
mp["Park"] = ;
tot = ;
for (i = ; i <= n; i++)
{
cin >> u >> v >> w;
if (!mp[u]) mp[u] = ++tot;
if (!mp[v]) mp[v] = ++tot;
e[i] = (Edge){mp[u],mp[v],w};
a[mp[u]].push_back(i);
a[mp[v]].push_back(i);
}
scanf("%d",&k);
visited[] = true;
for (i = ; i <= n; i++)
{
if (e[i].u == && !visited[e[i].v])
{
block++;
dfs(e[i].v);
}
if (e[i].v == && !visited[e[i].u])
{
block++;
dfs(e[i].u);
}
}
if (block > k)
{
printf("-1\n");
return ;
}
for (i = ; i <= block; i++) kruskal(i);
memset(val,0x3f,sizeof(val));
for (i = ; i <= n; i++)
{
if (e[i].u == && e[i].w < val[belong[e[i].v]])
{
val[belong[e[i].v]] = e[i].w;
p[belong[e[i].v]] = e[i].v;
} else if (e[i].v == && e[i].w < val[belong[e[i].u]])
{
val[belong[e[i].u]] = e[i].w;
p[belong[e[i].u]] = e[i].u;
}
}
for (i = ; i <= block; i++)
{
ans += val[i];
mst[][p[i]] = val[i];
mst[p[i]][] = val[i];
}
for (i = ; i <= k - block; i++)
{
mx = ;
ps = new_e = make_pair(,);
for (j = ; j <= n; j++)
{
if (e[j].u == && !mst[][e[j].v])
{
tmp = bfs(e[j].v);
if (mst[tmp.first][tmp.second] - e[j].w > mx)
{
ps = tmp;
new_e = make_pair(e[j].v,e[j].w);
mx = mst[tmp.first][tmp.second] - e[j].w;
}
}
if (e[j].v == && !mst[][e[j].u])
{
tmp = bfs(e[j].u);
if (mst[tmp.first][tmp.second] - e[j].w > mx)
{
ps = tmp;
new_e = make_pair(e[j].u,e[j].w);
mx = mst[tmp.first][tmp.second] - e[j].w;
}
}
}
if (mx == ) break;
ans -= mx;
mst[][new_e.first] = new_e.second;
mst[ps.first][ps.second] = ;
}
printf("Total miles driven: %d\n",ans); return ; }

[POJ 1639] Picnic Planning的更多相关文章

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

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

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

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

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

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

  4. poj 1639 Picnic Planning 度限制mst

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

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

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

  6. POJ1639 - Picnic Planning

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

  7. K度限制MST poj 1639

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

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

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

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

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

随机推荐

  1. unicode、UTF-8、UTF-16的历史

    1:中国人民通过对 ASCII 编码的中文扩充改造,产生了 GB2312 编码,可以表示6000多个常用汉字. 2:汉字实在是太多了,包括繁体和各种字符,于是产生了 GBK 编码,它包括了 GB231 ...

  2. border使用

    border属性 border-width  border-style  border-color  inherit border-style的值:none  dotted(点线)  dashed(虚 ...

  3. jenkins如何实现重新发布历史构建记录里的版本

    Jenkins以前打包都会将打出的拷贝放到历史版本里放到Daily_Result里,昨天不只是误操作还是系统问题,误将一个历史版本的包删掉了,而且这个包是之前比较稳定的一个版本,需要重新给客户发,所以 ...

  4. 推荐系统入门:作为Rank系统的推荐系统(协同过滤)

    知乎:如何学习推荐系统? 知乎:协同过滤和基于内容的推荐有什么区别? 案例:推荐系统实战?  数据准备:实现推荐栏位:重构接口:后续优化. 简书:实现实时推荐系统的三种方式?基于聚类和协同过滤:基于S ...

  5. Tinyxml2学习

    转自http://www.360doc.com/content/13/1223/16/3684846_339528825.shtml,尊重原文 什么是XML? XML全称EXtensible Mark ...

  6. Java RMI之HelloWorld经典入门案例

    Java RMI 指的是远程方法调用 (Remote Method Invocation).它是一种机制,能够让在某个 Java 虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法.可以用此方 ...

  7. matlab学习使用Button Group绘制不同的正弦曲线

    创建buttongroup控件---即按钮组 再添加三个radiobutton 对其设置 buttongroup控件改Title为绘制不同正弦曲线 第一个radiobutton的string改为sin ...

  8. 下拉框处理(select)

    在UI自动化测试过程中,经常会遇到一些下拉框,我们有三种可选方式来操作下拉框. 第一种方法 基于webdriver的两次click,很容易出现问题,不建议使用.(由于部分下拉框在点击一次后,失去焦点再 ...

  9. 【剑指Offer】4、重建二叉树

      题目描述:   输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列 ...

  10. 【JavaScript】通过封装自己的JSONP解决浏览器的跨域问题(Ajax跨域)

    问题引出:要发送Ajax请求,就必须使用HTTP请求?什么是跨域问题? 什么是跨域问题:如果两个页面中的协议.域名.端口.子域名任意有一项不同,两者之间所进行的访问行动就是跨域的,而浏览器为了安全问题 ...