POJ 3164 Command Network (最小树形图)
【题目链接】http://poj.org/problem?id=3164
【解题思路】百度百科:最小树形图 】里面有详细的解释,而Notonlysucess有精简的模板,下文有对其模板的一点解释,前提是对朱刘算法有所了解
【PS】这题没必要写题解,学了朱刘算法并不是表示你就锻炼到了思维了,在看最小树形图的形成时,对缩点那部分内容的算法和思路感叹不已,我想这就是算法的魅力!!
要理解的话,最好结合那张转载得很疯狂的图,但单看不行,自己将每个过程手动笔画一下更容易理解,开始搜题解的时候几乎都是用了模板,本来也想理解之后靠模板过了就算了以后如果遇到了这类题,二话不说直接上模板,后来自己还是手动的敲了一下,在OJ上提交了不差20次吧~~
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#define SIZE 102
#define MAXN 1 << 14 using namespace std; const double inf = << ;
const double eps = 1e-;
int nv, m, ne, root, cnt; struct Edge{
int u, v;
double cost;
};
struct Edge edge[MAXN];
double x[SIZE], y[SIZE];
int vis[SIZE];
int circle_id[SIZE];
double node[SIZE][SIZE];
double in[SIZE];
int pre[SIZE]; double dis(int a, int b)
{
return sqrt((x[a]-x[b])*(x[a]-x[b]) + (y[a]-y[b])*(y[a]-y[b]));
} void dfs(int cur)
{
vis[cur] = ;
for(int i=; i<=nv; ++i)
if(!vis[i] && node[cur][i] > inf)
dfs(i);
} bool exit_circle(double& res)
{
int update_id = ;
memset(vis, -, sizeof(vis));
memset(circle_id, -, sizeof(circle_id));
in[root] = ;
for(int i=; i<=nv; ++i)
{
res += in[i];
int v = i;
while(vis[v] != i && circle_id[v] == - && v != root)
{
vis[v] = i;
v = pre[v];
}
if(vis[v] == i)
{
for(int u = pre[v]; u != v; u = pre[u])
circle_id[u] = update_id;
circle_id[v] = update_id++;
}
}
if(update_id == ) return true;
for(int i=; i <= nv; ++i)
if(circle_id[i] == -)
circle_id[i] = update_id++; for(int i=; i < ne; ++i)
{
int u = edge[i].u;
int v = edge[i].v;
edge[i].u = circle_id[u];
edge[i].v = circle_id[v];
if(edge[i].u != edge[i].v) edge[i].cost -= in[v];
}
nv = update_id - ;
root = circle_id[root];
return false;
} bool insert()
{
for(int i=; i<=nv; ++i) in[i] = inf;
for(int i=; i<ne; ++i)
{
int& e = edge[i].v;
if(e == root) continue;
if(e != edge[i].u && in[e] > edge[i].cost)
{
in[e] = edge[i].cost;
pre[e] = edge[i].u;
}
}
for(int i=; i <= nv; ++i)
if(i != root && inf - in[i] < eps) return false;
return true;
} int main()
{
while(scanf("%d%d", &nv, &ne) != EOF)
{
for(int i=; i<=nv; ++i)
scanf("%lf%lf", &x[i], &y[i]);
cnt = ;
memset(node, , sizeof(node));
for(int i=; i<ne; ++i)
{
int u, v;
scanf("%d%d", &u, &v);
if(u != v)
edge[i].cost = dis(u, v);
else
edge[i].cost = inf;
edge[i].u = u;
edge[i].v = v;
}
root = ;
bool flag = false;
double ans = ;
do
{
if(!insert())
{
flag = true;
break;
}
}while(!exit_circle(ans));
if(flag) printf("poor snoopy\n");
else printf("%.2f\n", ans);
}
return ;
}
#include<cstdio>
#include<cstring>
#include<cmath>
#define SIZE 104
#define MAXN 10002 using namespace std; const double esp = 1e-;
const double inf = <<; int nv, ne; struct Edge{
int v, u;
double cost;
}edge[MAXN]; int vis[SIZE], circle_id[SIZE];
int pre[SIZE];
double in[SIZE];
double x[SIZE], y[SIZE]; double dis(int v, int u)
{
return sqrt((x[v]-x[u])*(x[v]-x[u]) + (y[v]-y[u])*(y[v]-y[u]));
} bool Traverse(double& res)
{//基本来自于模板
int root = ;
while(true)
{
for(int i = ; i <= nv; ++i) in[i] = inf+SIZE;
for(int i = ; i < ne; ++i)
{//集当前结点的各自最小的入边
int& u = edge[i].u;
if(in[u] > edge[i].cost && u != edge[i].v)
{
in[u] = edge[i].cost;
pre[u] = edge[i].v;
}
}
//在当前情况下如果有任何一个点没有最小边,说明不能形成最小树形图
//但这里没必要每次都判断,只在第一次进行判断即可
for(int i = ; i <= nv; ++i)
if(i != root && in[i] > inf) return false; int credit = ;
in[root] = ;
memset(vis, -, sizeof(vis));
memset(circle_id, -, sizeof(vis));
for(int i = ; i <= nv; ++i)
{//res为什么可以一直在加,首先第一次其就将有环没环的【结点最小边】的权值都加了,但就像缩点的理由所说的一样
//环中没必要加的一条边再后来的减掉了,看下面的 ‘##’处
res += in[i];
int v = i;
while(vis[v] != i && circle_id[v] == - && v != root)
{//这里并不能将 circle_id[v] == -1 这个条件提取出来提前判断
//一个结点假设其不在环内,那么其结果是退后到根点或者退后到一个结点是环内点(已判断其为环内的点)
vis[v] = i;
v = pre[v];
}
if(vis[v] == i)
{//其实这里已经在缩点,将环内的点写入一个统一的结点编号
for(int u = pre[v]; u != v; u = pre[u])
circle_id[u] = credit;
circle_id[v] = credit++;
}
}
if(credit == ) return true;
for(int i = ; i <= nv; ++i)
if(circle_id[i] == -) circle_id[i] = credit++;
for(int i = ; i < ne; ++i)
{//如果更新后两个结点有相同的编号,其作用体现在上面求最小边中 :u != edge[i].v的判断
int u = edge[i].u;
int v = edge[i].v;
edge[i].u = circle_id[u];
edge[i].v = circle_id[v];
// ## 如果这条最小边不在环内(即这里判断的意义),因为之前加了最小边的值,那就得减去其值。
//那么减掉之后就可能变成了零或比之前短 ;其实这里不用判断条件的 如果是在环内
//其因为两端的结点相同对后来没有了影响,这是剩下最后一种情况了,就是一结点在环内(能缩点的条件)
if(edge[i].v != edge[i].u)
edge[i].cost -= in[u];
}
nv = credit - ;
root = circle_id[root];
}
return true;
} int main()
{
while(scanf("%d%d", &nv, &ne) != EOF)
{
for(int i = ; i <= nv; ++i)
scanf("%lf%lf", &x[i], &y[i]);
for(int i = ; i < ne; ++i)
{//这里就开始处理掉自环的情况,把自环的距离设置得比预定的最大值还大
scanf("%d%d", &edge[i].v, &edge[i].u);
edge[i].cost = edge[i].v == edge[i].u ? inf+MAXN : dis(edge[i].v, edge[i].u);
}
double res = ;
if(Traverse(res)) printf("%.2f\n", res); //这里用f好像跟提交的方式有关,FAQ里有解释
else printf("poor snoopy\n");
}
return ;
}
POJ 3164 Command Network (最小树形图)的更多相关文章
- POJ 3164 Command Network 最小树形图
题目链接: 题目 Command Network Time Limit: 1000MS Memory Limit: 131072K 问题描述 After a long lasting war on w ...
- POJ 3164 Command Network 最小树形图模板
最小树形图求的是有向图的最小生成树,跟无向图求最小生成树有很大的区别. 步骤大致如下: 1.求除了根节点以外每个节点的最小入边,记录前驱 2.判断除了根节点,是否每个节点都有入边,如果存在没有入边的点 ...
- POJ 3164 Command Network 最小树形图 朱刘算法
=============== 分割线之下摘自Sasuke_SCUT的blog============= 最 小树形图,就是给有向带权图中指定一个特殊的点root,求一棵以root为根的有向生成树T, ...
- POJ3436 Command Network [最小树形图]
POJ3436 Command Network 最小树形图裸题 傻逼poj回我青春 wa wa wa 的原因竟然是需要%.2f而不是.2lf 我还有英语作业音乐作业写不完了啊啊啊啊啊啊啊啊啊 #inc ...
- poj 3164 Command Network
http://poj.org/problem?id=3164 第一次做最小树形图,看着别人的博客写,还没弄懂具体的什么意思. #include <cstdio> #include < ...
- POJ 3164——Command Network——————【最小树形图、固定根】
Command Network Time Limit: 1000MS Memory Limit: 131072K Total Submissions: 15080 Accepted: 4331 ...
- POJ 3164 Command Network(最小树形图模板题+详解)
http://poj.org/problem?id=3164 题意: 求最小树形图. 思路: 套模板. 引用一下来自大神博客的讲解:http://www.cnblogs.com/acjiumeng/p ...
- POJ 3164 Command Network ( 最小树形图 朱刘算法)
题目链接 Description After a long lasting war on words, a war on arms finally breaks out between littlek ...
- poj 3164 Command Network(最小树形图模板)
Command Network http://poj.org/problem?id=3164 Time Limit: 1000MS Memory Limit: 131072K Total Subm ...
随机推荐
- Newtonsoft.Json高级用法 1.忽略某些属性 2.默认值的处理 3.空值的处理 4.支持非公共成员 5.日期处理 6.自定义序列化的字段名称
手机端应用讲究速度快,体验好.刚好手头上的一个项目服务端接口有性能问题,需要进行优化.在接口多次修改中,实体添加了很多字段用于中间计算或者存储,然后最终用Newtonsoft.Json进行序列化返回数 ...
- Using Git subtrees to split a repository
https://lostechies.com/johnteague/2014/04/04/using-git-subtrees-to-split-a-repository/ We are in a p ...
- 在AChartEngine上绘图,手指标记当前位置
最近要做一个绘图项目,需要在ACE折线图上再绘出一条红标记当前坐标,经过这几天研究,可以给大家分享一下了.先上效果图吧! 代码里的注释还是比较清楚,就不作说明了. package com.exampl ...
- javascirpt历史澄清误解基本概念特点编程语言web2.0网页javascript - javascirpt知识大全
目录1历史 2澄清误解 3基本概念 4特点 5与Java的不同 6开发工具 历史 大概在1992年,一家称作Nombas的公司开始开发一种叫做C减减(C-minus-minus,简称Cmm)的嵌入式脚 ...
- JSON 之 SuperObject(8): 关于乱码的几种情况 - 向 Henri Gourvest 大师报告
这几天学习 JSON - SuperObject, 非常幸运地得到了其作者 Henri Gourvest 大师的同步指点! (Henri 大师也是 DSPack 和 GDI+ 头文件的作者; 大师是法 ...
- Qt之QHeaderView排序
简述 在Windows中我们经常会遇到表头排序,比如可以对文件按照名称.修改日期.类型.大小进行排序,方便我们统一的归类查找. Qt中,我们可以通过点击表头来对QTableView或QTreeView ...
- 解同余式ax ≡ c(mod m)
将式子变形为 ax-c=my 可以看出原式有解当且仅当线性方程ax-my=c有解 设g = gcd(a, m) 则所有形如ax-my的数都是g的倍数 因此如果g不整除c则原方程无解. 下面假设g整除c ...
- C# list installed softwares
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Product&q ...
- Qt 获取usb设备信息 hacking
/************************************************************************** * Qt 获取usb设备信息 hacking * ...
- 20160201.CCPP体系详解(0011天)
内容概要:C语言基本数据类型及运算题库(含答案) 第二章 基本数据类型及运算 一.选择题 1. 若以下选项中的变量已正确定义,则正确的赋值语句是[C]. A) x1=26.8%3; B) 1+2=x2 ...