【POJ1734】Sightseeing trip

题目链接:https://www.acwing.com/problem/content/346/

题目大意:确定无向带权图上至少包含 3 个节点的最小环

solution

一道无向图上的最小环问题 , 考虑 \(Floyd\) , 设 \(i\) 到 \(j\) 间的道路长为 \(f[i][j]\) , 最短路径长 \(g[i][j]\) , 若每次 \(Floyd\) 最外层 遍历到 \(k\) 时 , \(g[i][j]\) 决定了 \(i\) 到 \(j\) 间经过节点编号不超过 \(k\) 的最短路径 , 不妨以 \(k\) 为环上的节点 , 枚举 \(i\) 和 \(j\) , 即是枚举 \(k\) 在环上的相邻节点 , 那么这个环的最小长度为\(f[i][k] + f[k][j] + g[i][j]\) , 这样就可以找出环上节点编号不超过 \(k\) 的最小环 , 由对称性 , 最终可以遍历到每一个最小环

拓展 : 对于有向图上的最小环 , 可以依次枚举起点 \(s\) , 再在 \(dijstra\) 中 \(s\) 向外拓展后 , 把 \(shortestpath[s]\) 设为极大值 , 最终的 \(shortestpath[s]\) 即为从 \(s\) 开始的最小环的长度 , 笔者在这不多加赘述

时间复杂度 : \(O(n^3)\)

code

#include<bits/stdc++.h>
using namespace std;
template <typename T> inline void read(T &FF) {
    int RR = 1; FF = 0; char CH = getchar();
    for(; !isdigit(CH); CH = getchar()) if(CH == '-') RR = -RR;
    for(; isdigit(CH); CH = getchar()) FF = FF * 10 + CH - 48;
    FF *= RR;
}
inline void file(string str) {
    freopen((str + ".in").c_str(), "r", stdin);
    freopen((str + ".out").c_str(), "w", stdout);
}
const int N = 105;
int g[N][N], ans = INT_MAX, f[N][N];
int pos[N][N], n, m;
queue<int> path;
void get_path(int xi, int yi) {
    if(pos[xi][yi] == 0) return;
    get_path(xi, pos[xi][yi]);
    path.push(pos[xi][yi]);
    get_path(pos[xi][yi], yi);
}
int main() {
    //file("");
    int u, v, w;
    read(n), read(m);
    memset(g, 0x3f, sizeof(g));
    memset(f, 0x3f, sizeof(f));
    for(int i = 1; i <= n; i++) f[i][i] = g[i][i] = 0;
    for(int i = 1; i <= m; i++) {
        read(u), read(v), read(w);
        g[u][v] = g[v][u] = min(g[u][v], w);
        f[u][v] = f[v][u] = g[u][v];
    }
    ans = f[0][0];
    for(int k = 1; k <= n; k++) {
        for(int i = 1; i < k; i++)
            for(int j = i + 1; j < k; j++)
                if((long long)g[i][j] + f[i][k] + f[k][j] < ans) {
                    ans = g[i][j] + f[i][k] + f[k][j];
                    while(!path.empty()) path.pop();
                    path.push(i);
                    get_path(i, j);
                    path.push(j); path.push(k);
                }
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                if(g[i][k] + g[k][j] < g[i][j]) {
                    g[i][j] = g[i][k] + g[k][j];
                    pos[i][j] = k;
                }
    }
    if(path.empty()) {
        puts("No solution.");
        return 0;
    }
    while(!path.empty()) cout << path.front() << " ", path.pop();
    cout << endl;
    return 0;
}

原文地址:https://www.cnblogs.com/magicduck/p/12241605.html

时间: 2024-10-16 01:24:06

【POJ1734】Sightseeing trip的相关文章

【POJ1734】Sightseeing Trip 无向图最小环

题目大意:给定一个 N 个顶点的无向图,边有边权,如果存在,求出该无向图的最小环,即:边权和最小的环,并输出路径. 题解:由于无向图,且节点数较少,考虑 Floyd 算法,在最外层刚开始遍历到第 K 号节点时,\(d[i][j]\) 中记录着经过前 k-1 个点,从 i 到 j 的最短距离.因此,可以依次考虑每一个结构:\(\{d[i][j]+G[i][k]+G[k][j] \}\),这便是一个环形结构,每次更新答案贡献即可. 至于路径输出,\(get\_path(int\ i,int\ j)\

【POJ3621】Sightseeing Cows 分数规划

[POJ3621]Sightseeing Cows 题意:在给定的一个图上寻找一个环路,使得总欢乐值(经过的点权值之和)/ 总时间(经过的边权值之和)最大. 题解:显然是分数规划,二分答案ans,将每条边的权值变成(ans*边权-2*起始点点权),然后我们希望找出一个环,使得环上的总边权<0 (一开始我把题意理解错了,题中给的是单向边,我把它当成是双向边+每条边只能走一次了~,想出一堆做法都接连pass掉) 然后就直接用SPFA判负环就好了嘛!由于原图不一定联通,所以一开始就把所有点都入队就完事

【POJ】【1637】Sightseeing tour

网络流/最大流 愚人节快乐XD 这题是给一个混合图(既有有向边又有无向边),让你判断是否有欧拉回路…… 我们知道如果一个[连通]图中每个节点都满足[入度=出度]那么就一定有欧拉回路…… 那么每条边都可以贡献一个出度出来,对于一条边u->v: 连S->edge cap=1; 如果是有向边,就连 edge->v cap=1; 否则(无向边)连edge->u cap=1, edge->v cap=1; 然后每个点的总度数我们是知道的……那么它最后的[出度]就等于 总度数/2.(这个

【POJ3621】Sightseeing Cows

Sightseeing Cows Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8331   Accepted: 2791 Description Farmer John has decided to reward his cows for their hard work by taking them on a tour of the big city! The cows must decide how best to

【POJ1637】Sightseeing tour

Description The city executive board in Lund wants to construct a sightseeing tour by bus in Lund, so that tourists can see every corner of the beautiful city. They want to construct the tour so that every street in the city is visited exactly once.

【POJ1637】Sightseeing tour 混合图求欧拉回路存在性 网络流、

题意:多组数据,最后的0/1表示0无向1有向. 问是否存在欧拉回路. 题解:无向边给它任意定个向. 首先欧拉回路中点入度=出度. 然后发现每个无向边如果修改个方向,原来的入点的入度+1,出度-1,出点反之. 然后我们不妨对入度和出度不同的点跟源汇中之一连边,容量为入出度差一半(每改一条边差-2) 然后原来的无向边联系图中各点,容量1,最后check if(maxflow==sum差/4). 这都没看懂的弱菜们不妨出度多的连源,入度多的连汇,容量为入出度差一半,然后按无向边的定向给它在网络流图中定

POJ1734 Sightseeing trip 【Floyd】+【最小环】+【路径记录】

Sightseeing trip Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4830   Accepted: 1857   Special Judge Description There is a travel agency in Adelton town on Zanzibar island. It has decided to offer its clients, besides many other attra

POJ1734 Sightseeing trip【Floyd】【最小环】

Sightseeing trip Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 5038 Accepted: 1930 Special Judge Description There is a travel agency in Adelton town on Zanzibar island. It has decided to offer its clients, besides many other attractions

POJ 1041 John&#39;s trip 无向图的【欧拉回路】路径输出

欧拉回路第一题TVT 本题的一个小技巧在于: [建立一个存放点与边关系的邻接矩阵] 1.先判断是否存在欧拉路径 无向图: 欧拉回路:连通 + 所有定点的度为偶数 欧拉路径:连通 + 除源点和终点外都为偶数 有向图: 欧拉回路:连通 + 所有点的入度 == 出度 欧拉路径:连通 + 源点 出度-入度=1 && 终点 入度 - 出度 = 1 && 其余点 入度 == 出度: 2.求欧拉路径 : step 1:选取起点(如果是点的度数全为偶数任意点为S如果有两个点的度数位奇数取一