最小环(floyd以及dijkstra实现+例题)
##最小环定义
最小环是指在一个图中,有n个节点构成的边权和最小的环(n>=3)。
一般来说,最小环分为有向图最小环和无向图最小环。
##最小环算法:
###直接暴力:
设$u$和$v$之间有一条边长为$w$的边,$dis(u,v)$表示删除$u$和$v$之间的连边之后,$u$和$v$之间的最短路。那么最小环是$dis(u,v)+w$总时间复杂度$O(n^2m)$。
###Dijkstra
任意一个环,假设连接$u$和$v$,我们都可以看做删除$u$与$v$的直接连边之后的$u$到$v$的最短路再加上该边,若边数为$m$,那么找出最小环要跑$m$次Dijkstra,复杂度为$O(n(n+m)log)$
###Floyd
记原图$u$,$v$之间边权为$mp(u,v)$,floyd算法在外层循环到第k个点时(还没开始第k次循环),最短路数组$g$中,$g(u,v)$表示的是从$u$到$v$且仅经过编号$[1,k)$区间中的点的最短路。
最小环至少有三个顶点,设其中编号最大的顶点编号为$w$,环上与$w$相邻两侧的两个点为$u$,\(v\),则在最外层循环枚举到$k=w$时,该环的长度为$g(u,v)+mp(v,w)+mp(w,u)$,所以在循环时候$i$,$j$只需枚举到$i<k$,\(j<k\),更新答案即可
复杂度:\(O(n^3)\)
##下面是实现参考:
for (int k = 1; k <= n; k++)
{
for (int i = 1; i < k; i++)
for (int j = i + 1; j < k; j++)
ans = min(ans, g[i][j] + mp[i][k] + mp[k][j]);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
}
##例题 HDU 1599
此处输入链接的描述
裸题= =,没啥东西,就去个重
#include <bits/stdc++.h>
using namespace std;
/* freopen("k.in", "r", stdin);
freopen("k.out", "w", stdout); */
//clock_t c1 = clock();
//std::cerr << "Time:" << clock() - c1 <<"ms" << std::endl;
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#define de(a) cout << #a << " = " << a << endl
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef vector<int, int> VII;
#define inf 0x3f3f3f3f
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MAXN = 1e2 + 7;
const ll MAXM = 1e6 + 7;
const ll MOD = 1e9 + 7;
const double eps = 1e-6;
const double pi = acos(-1.0);
ll g[MAXN][MAXN];
ll mp[MAXN][MAXN]; //原图
int n, m;
void init()
{
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
mp[i][j] = i == j ? 0 : inf;
}
int main()
{
while (~scanf("%d%d", &n, &m))
{
init();
memset(g, inf, sizeof(g));
for (int i = 0; i < m; i++)
{
int u, v;
ll val;
scanf("%d%d%lld", &u, &v, &val);
if (val < mp[u][v])
mp[v][u] = mp[u][v] = val;
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
g[i][j] = mp[i][j];
ll ans = inf;
for (int k = 1; k <= n; k++)
{
for (int i = 1; i < k; i++)
for (int j = i + 1; j < k; j++)
ans = min(ans, g[i][j] + mp[i][k] + mp[k][j]);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
}
if (ans == inf)
printf("It's impossible.\n");
else
printf("%d\n", ans);
}
return 0;
}
参考oiwiki
##dijkstra版拓展题 HDU-6005 Pandaland
HDU6005
###解题思路:
也是最小环(当然啦啊喂),不过点是坐标的形式,需要转换为序号,之后记录跑的起点和终点,dijkstra中不跑这条边即可,可以稍微剪剪枝(超重要诶),如果dijkstra中当前最短边和直连边权值之和大于ans,直接break,会快很多(迫真),这题没重边,所以不用去
#include <bits/stdc++.h>
using namespace std;
/* freopen("k.in", "r", stdin);
freopen("k.out", "w", stdout); */
//clock_t c1 = clock();
//std::cerr << "Time:" << clock() - c1 <<"ms" << std::endl;
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#define de(a) cout << #a << " = " << a << endl
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef vector<int, int> VII;
#define inf 0x3f3f3f3f
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MAXN = 8e3 + 7;
const ll MAXM = 1e6 + 7;
const ll MOD = 1e9 + 7;
const double eps = 1e-6;
const double pi = acos(-1.0);
struct node
{
int v, c;
node(int a = 0, int b = 0) { v = a, c = b; }
bool operator<(const node &a) const
{
if (c == a.c)
return v < a.v;
else
return c > a.c;
}
};
struct Edge
{
int v, cost;
Edge(int _v = 0, int _cost = 0) { v = _v, cost = _cost; }
};
struct EE
{
int u, v, w;
EE(int _u = 0, int _v = 0, int _w = 0) { u = _u, v = _v, w = _w; }
} E[MAXN];
vector<Edge> G[MAXN];
bool vis[MAXN];
int dist[MAXN];
//点的编号从1开始
int ans;
void Dijkstra(int n, int start, int ed, int val)
{
memset(vis, false, sizeof(vis));
for (int i = 1; i <= n; i++)
dist[i] = inf;
priority_queue<node> que;
while (!que.empty())
que.pop();
dist[start] = 0;
que.push(node(start, 0));
node temp;
while (!que.empty())
{
temp = que.top();
que.pop();
int u = temp.v;
if (temp.c + val > ans)
break; //该点最短距离+start与ed的直连边长大于ans,说明不是最小环,直接break
if (vis[u])
continue;
vis[u] = true;
for (int i = 0; i < G[u].size(); i++)
{
int v = G[u][i].v;
int cost = G[u][i].cost;
if ((u == start && v == ed) || (v == ed && u == start)) //不经过start-ed的直达边
continue;
if (!vis[v] && dist[v] > dist[u] + cost)
{
dist[v] = dist[u] + cost;
que.push(node(v, dist[v]));
}
}
}
}
void addedge(int u, int v, int w)
{
G[u].push_back(Edge(v, w));
}
int cnt = 0;
void init(int n)
{
for (int i = 1; i <= n; i++)
G[i].clear();
cnt=0;
}
/* 题目没重边,不然还得去一波重 */
int main()
{
int t;
scanf("%d", &t);
for (int tt = 1; tt <= t; tt++)
{
map<PII, int> mp;
int m;
scanf("%d", &m);
init(m << 1);
for (int i = 0; i < m; i++)
{
int x1, y1, x2, y2, w;
scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &w);
if (!mp[PII(x1, y1)])
mp[PII(x1, y1)] = ++cnt;
if (!mp[PII(x2, y2)])
mp[PII(x2, y2)] = ++cnt;
int u = mp[PII(x1, y1)], v = mp[PII(x2, y2)];
addedge(u, v, w);
addedge(v, u, w);
E[i] = EE(u, v, w); //存原边
}
ans = inf;
for (int i = 0; i < m; i++)
{
if (ans < E[i].w)
continue;
Dijkstra(cnt, E[i].u, E[i].v, E[i].w);
ans = min(ans, dist[E[i].v] + E[i].w);
}
printf("Case #%d: %d\n", tt, ans == inf ? 0 : ans);
}
return 0;
}
最小环(floyd以及dijkstra实现+例题)的更多相关文章
- hdu1874 畅通project续 最短路 floyd或dijkstra或spfa
Problem Description 某省自从实行了非常多年的畅通project计划后.最终修建了非常多路.只是路多了也不好,每次要从一个城镇到还有一个城镇时,都有很多种道路方案能够选择.而某些方案 ...
- 图论——最短路:Floyd,Dijkstra,Bellman-Ford,SPFA算法及最小环问题
一.Floyd算法 用于计算任意两个节点之间的最短路径. 参考了five20的博客 Floyd算法的基本思想如下:从任意节点A到任意节点B的最短路径不外乎2种可能,1是直接从A到B,2是从A经过若干个 ...
- timus1004 最小环()Floyd 算法
通过别人的数据搞了好久才成功,果然还是不够成熟 做题目还是算法不能融会贯通 大意即找出图中至少3个顶点的环,且将环中点按顺序输出 用floyd算法求最小环 因为floyd算法求最短路径是通过中间量k的 ...
- 最小生成树(prime算法 & kruskal算法)和 最短路径算法(floyd算法 & dijkstra算法)
一.主要内容: 介绍图论中两大经典问题:最小生成树问题以及最短路径问题,以及给出解决每个问题的两种不同算法. 其中最小生成树问题可参考以下题目: 题目1012:畅通工程 http://ac.jobdu ...
- 图论之最短路径(1)——Floyd Warshall & Dijkstra算法
开始图论学习的第二部分:最短路径. 由于知识储备还不充足,暂时不使用邻接表的方法来计算. 最短路径主要分为两部分:多源最短路径和单源最短路径问题 多源最短路径: 介绍最简单的Floyd Warshal ...
- 最短路径——Floyd,Dijkstra(王道)
题目描述: 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt.但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线 ...
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
几大最短路径算法比较 转自:http://blog.csdn.net/v_july_v/article/details/6181485 几个最短路径算法的比较: Floyd 求多 ...
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较(转)
几大最短路径算法比较 几个最短路径算法的比较:Floyd 求多源.无负权边(此处错误?应该可以有负权边)的最短路.用矩阵记录图.时效性较差,时间复杂度O(V^3). Floy ...
- 图的连通性问题之连通和最小环——Floyd算法
Floyd 判断连通性 d[i][j]仅表示i,j之间是否联通 ;k<=n;k++) ;i<=n;i++) ;j<=n;j++) dis[i][j]=dis[i][j]||(dis[ ...
随机推荐
- ecshop数据结构
ecshop数据结构 2.7.2版本,数据库表 共88张表 注: 1.颜色为蓝色的字,有待讨论验证的地方. 2.颜色为红色的字,是新增的字段.(改文档是基于网上下载的老版本的数据字典修改而成,已经检 ...
- python接口自动化测试-unittest-生成测试报告
用例的管理问题解决了后,接下来要考虑的就是报告我问题了,这里生成测试报告主要用到 HTMLTestRunner.py 这个模块,下面简单介绍一下如何使用: 一.下载HTMLTestRunner下载: ...
- Java网络编程——UDP聊天程序
UDP简介 UDP协议的全称是用户数据报,在网络中它与TCP协议一样用于处理数据报.在OSI模型中,UDP位于第四层--传输层,处于IP协议额上一层.UDP有不提供数据报分组.组装以及不能对数据报排序 ...
- 探究Dubbo的拓展机制: 上
这篇博文是我决心深度学习Dubbo框架时记录的笔记, 主题是Dubbo的拓展点, 下面的几个部分相对来说比较零散, 貌似是不和主题挂钩的 , 并且是一些很冷门的知识点 , 但是它们确实是深入学习Dub ...
- iSO垂直滑动条VerticalSlider
由于项目需要实现一个垂直的Slider,滑动条使用UIlabel实现,按钮使用UIButton,按钮可以设置背景图片,代码如下 VerticalSlider.h // // VerticalSlide ...
- ACM北大暑期课培训第二天
今天继续讲的动态规划 ... 补充几个要点: 1. 善于利用滚动数组(可减少内存,用法与计算方向有关) 2.升维 3.可利用一些数据结构等方法使代码更优 (比如优先队列) 4.一般看到数值小的 (十 ...
- codevs 3981 动态最大子段和(线段树)
题目传送门:codevs 3981 动态最大子段和 题目描述 Description 题目还是简单一点好... 有n个数,a[1]到a[n]. 接下来q次查询,每次动态指定两个数l,r,求a[l]到a ...
- BitSet 的使用
BitSet 的简单介绍 BitSet,即位图,是位操作的对象,值只有 0 或 1(即 false 或 true). Java 的 BitSet 内部维护着一个 long 数组,默认初始化时数组的长度 ...
- 详细解析Java虚拟机的栈帧结构
欢迎关注微信公众号:万猫学社,每周一分享Java技术干货. 什么是栈帧? 正如大家所了解的,Java虚拟机的内存区域被划分为程序计数器.虚拟机栈.本地方法栈.堆和方法区.(什么?你还不知道,赶紧去看看 ...
- Java 利用Map集合计算一个字符串中每个字符出现的次数
步骤分析 1.给出一串字符串,字符串中可以包含字母.数字.符号等等. 2.创建一个Map集合,key是字符串中的字符,value是字符的个数. 3.遍历字符串,获取每一个字符. 5.使用获取到的字符, ...