Codeforces1204C. Anna, Svyatoslav and Maps (贪心 + Floyd)

题目链接:传送门



题目大意:

给出n<=100的有向图,和路径p,求p的最短子序列v,使得依次经过v中所有点的路径为p。



思路:

题意其实就是让我们求路径上的一些关键点v,对于所有的关键点:vi到vi+1的最短路的长度,等于vi到vi+1这两个点在序列p中的下标的差,且vi到vi+2的最短路的长度,小于vi到vi+2在序列p中的下标的差。

如果用dis[u][v] 表示:在题目给出的有向图中,从u出发到v的最短路径的长度。则:

1、p1和pm都是关键点。

2、假设u是之前的最后一个关键点,如果dis[u][pi+1] != dis[u][pi] + 1,则pi就是下一个关键点。

那么用Floyd预处理任意两点间的最短路,就可以O(m)地跑一遍数组p,得到所有的关键点,就是答案了。



代码:O(n3+m)

#include <bits/stdc++.h>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 105
#define M 1000005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x) // be conscious if mask x exceeds int
#define sz(x) ((int)x.size())
#define lson(x) (x<<1)
#define rson(x) (x<<1|1)
#define mp(a,b) make_pair(a, b)
#define endl ‘\n‘
#define lowbit(x) (x&-x)

using namespace std;
typedef long long ll;
typedef double db;

/** fast read **/
template <typename T>
inline void read(T &x) {
    x = 0; T fg = 1; char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == ‘-‘) fg = -1;
        ch = getchar();
    }
    while (isdigit(ch)) x = x*10+ch-‘0‘, ch = getchar();
    x = fg * x;
}
template <typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }

int n, m;
int a[N][N];
bool cant[N][N];
int p[M];

void Folyd() {
    memset(cant, false, sizeof cant);
    for (int k = 1; k <= n; k++) {
        for (int i = 1; i <= n; i++) if (i != k) {
            for (int j = 1; j <= n; j++) if (j != i && j != k) {
                if (a[i][j] > a[i][k] + a[k][j])
                    a[i][j] = a[i][k] + a[k][j];
                else if (a[i][j] == a[i][k] + a[k][j]) {
                    cant[i][j] = true;
                }
            }
        }
    }
}

vector <int> ans;
int main()
{
    read(n);
    for (int i = 1; i <= n; i++) {
        string s; cin >> s;
        for (int j = 1; j <= n; j++) {
            if (j == i)
                a[i][j] = 0;
            else if (s[j-1] == ‘1‘)
                a[i][j] = 1;
            else
                a[i][j] = 1e5;
        }
    }
    read(m);
    for (int i = 1; i <= m; i++) {
        read(p[i]);
    }
    Folyd();
    int u = p[1];
    ans.push_back(u);
    for (int i = 2; i <= m; i++) {
        if (a[u][p[i]] > a[u][p[i-1]])
            continue;
        u = p[i-1];
        ans.push_back(u);
    }
    ans.push_back(p[m]);
    cout << ans.size() << endl;
    for (int i = 0; i < sz(ans); i++) {
        printf("%d%c", ans[i], i == sz(ans)-1 ? ‘\n‘ : ‘ ‘);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Lubixiaosi-Zhaocao/p/11634811.html

时间: 2024-11-18 02:54:45

Codeforces1204C. Anna, Svyatoslav and Maps (贪心 + Floyd)的相关文章

[最短路,floyd] Codeforces 1204C Anna, Svyatoslav and Maps

题目:http://codeforces.com/contest/1204/problem/C C. Anna, Svyatoslav and Maps time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output The main characters have been omitted to be short. You are give

CF1204C Anna, Svyatoslav and Maps

题意 在给定的序列P中求一个子序列,使得在图中按照该子序列进行最短路径移动时可以完整经过原序列P code #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #define maxn 105 #define maxm 1000010 #define inf 0x3f3f3f3f using namespace std ; int n ,m , idx

Codeforces Round #581 (Div. 2)

A.BowWow and the Timetable 题目连接 题目大意 给你一个以二进制方式来表示数字\(n\)的字符串,问\(4^k < n\)数字的个数. 解题思路 题目给的数字是以二进制的方式给的,那么结合二进制数字的特点,可以发现每个\(4^k\)用二进制表示最前面的那个1都是在奇数位置,那么如果给的字符串长度是偶数,直接除以2:如果是奇数的话,加1除以2,并且判断最高位1是否满足条件. AC代码 #include <bits/stdc++.h> using namespace

CF1204C

CF1204C-Anna, Svyatoslav and Maps 题意: 题目传送门 不想说了,阅读题. 解法: 先用floyd跑出各顶点间的最短路.把p(1)加入答案,然后沿着题目给的路径序列遍历,如果答案中的最后一个顶点到当前遍历到的顶点的最短距离,小于原序列中两点的距离和,则答案加上p(i-1),并且继续遍历路径,遍历完之后在最后加上p(m) CODE: #include<iostream> #include<cstdio> #include<cstring>

bzoj 2165: 大楼【Floyd+矩阵乘法+倍增+贪心】

1<<i的结果需要是long long的话i是long long是没用的--要写成1ll<<i--我别是个傻子吧 虽然写的是二进制贪心,但是我觉得二分可能更好写吧(但是会慢) 首先把矩阵乘法转换成Floyd的形式,注意是进行一次更新,也就是另开一个数组使得更新之后每个[i][j]都变成经过一或两段路,(i,j)之间的最长路 然后就可以倍增了,一直相乘就会变成经过一二四六八-段路,(i,j)之间的最长路,这里把倍增过程记下来 直到某次相乘之后符合要求(也就是[1][x]的最长路大于等

[C++] 多源最短路径(带权有向图):【Floyd算法(动态规划法)】 VS nX Dijkstra算法(贪心算法)

1 Floyd算法 1.1 Code /** * 弗洛伊德(Floyd)算法: 1 解决问题: 多源最短路径问题 求每一对顶点之间的最短路径 Background: 带权有向图 2 算法思想: 动态规划(DP, Dynamic Programming) 3 时间复杂度: O(n^3) */ #include<stdio.h> #include<iostream> using namespace std; // 1 定义图模型(邻接矩阵表示法)的基本存储结构体 # define Ma

求最短路径的三种算法: Ford, Dijkstra和Floyd

Bellman-Ford算法 Bellman-Ford是一种容易理解的单源最短路径算法, Bellman-Ford算法需要两个数组进行辅助: dis[i]: 存储顶点i到源点已知最短路径 path[i]: 存储顶点i到源点已知最短路径上, i的前一个顶点. 若图有n个顶点, 则图中最长简单路径长度不超过n-1, 因此Ford算法进行n-1次迭代确保获得最短路径. Ford算法的每次迭代遍历所有边, 并对边进行松弛(relax)操作. 对边e进行松弛是指: 若从源点通过e.start到达e.sto

最短路(floyd/dijkstra/bellmanford/spaf 模板)

floyd/dijkstra/bellmanford/spaf 模板: 1. floyd(不能处理负权环,时间复杂度为O(n^3), 空间复杂度为O(n^2)) floyd算法的本质是dp,用dp[k][i][j]表示以(1....k)为中间点,i, j之间的最短距离为多少,dp[0][i][j]即为原矩阵图. dp[k][i][j]可以由dp[k-1][i][j]转移得到,即不经过 k 点i, j之间的最短距离为多少, 也可以由dp[k-1][i][k]+dp[k-1][k][j]转移得到,即

World Finals 1996 Uva (Floyd求闭包)

思路:用Floyd求传递闭包. 附:逗号后的空格没看到,WA了好多次…….还有就是强连通分量也可以做,但是对这个题来说太麻烦,而且不方便输出,. 代码如下: #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<map> using namespace std; int n,m; map<string,int> ma; map&l