[fzu 2271]不改变任意两点最短路至多删的边数

题目链接:http://acm.fzu.edu.cn/problem.php?pid=2271

题目中说每条边的边权都是[1,10]之间的整数,这个条件非常关键!以后一定要好好读题啊……

做10次循环,第i次循环加边权为i的边,如果这条边小于当前两点间最短路,就加边,更新两点距离;否则就不要这个边。

每次循环过后,做一次Floyd。至多做10次Floyd。

有一个猜想,比赛的时候就想到了:从小到大加边,如果这个边比这两点之间的最短距离小,就要,否则就不要。这个猜想不会证……

但是只想到了每次更改距离以后都做一次Floyd,没有想到一块加权值相同的边,然后再做Floyd。这里就假设上面的猜想是正确的,然后证明一下统一做Floyd的方法也是正确的吧。

假设dis[][]维护着两点间的最短距离。

首先,对于未经优化的方法,如果有一条边加入了,说明这条边的权比两点的最短路短,如果没有随时维护,只维护到了上次权值不同的最后一条边,由于dis随着维护是越来越小的,所以现在的dis也显然大于这个边权,因此对于没有优化的方法,这条边会加进去。

然后,对于未经优化的方法,如果有一条边没有加入,说明这条边的权w不比两点的最短路短,如果没有随时维护,只维护到了上次权值不同的最后一条边,由于用[1,w-1]的边构成的最短路已经得到,假设这条权值是w的边在优化后会加入,也就是说当前的dis>w,而优化以前没有加入,说明dis‘<=w,所以意思就是,加入了一些权值为w的边以后,dis变得<=w了,那这个dis‘只能是=w了。既然是权值为w的最短路,要么是用权值为w的边得到的,那此时dis应该也=w了,因为每遇到一个w的边都会更新距离。要么是用[1,w-1]的边构成的,那这个在[1,w-1]之后就应该已经维护出来了。这两种情况都与dis>w矛盾。所以假设失败,这条边在优化以后还是不会加入。

所以加不加入在优化前后是一样的。

#include<cstdio>
#include<cstring>

const int maxn=105;
const int maxm=40005;
const int INF=0x3f3f3f3f;

struct Edge
{
    int u,v,w;
}edge[maxm];
int dis[maxn][maxn];

int main()
{
    int t;
    scanf("%d",&t);
    for (int cas=1;cas<=t;cas++)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for (int i=0;i<m;i++)
        {
            scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
        }
        memset(dis,INF,sizeof(dis));
        for (int i=1;i<=n;i++) dis[i][i]=0;
        int ans=0;
        for (int z=1;z<=10;z++)
        {
            for (int e=0;e<m;e++)
            {
                if (edge[e].w==z)
                {
                    int u=edge[e].u;
                    int v=edge[e].v;
                    if (z<dis[u][v])
                    {
                        dis[u][v]=z;
                        dis[v][u]=z;
                        ans++;
                    }
                }
            }
            for (int k=1;k<=n;k++)
                for (int i=1;i<=n;i++)
                    for (int j=1;j<=n;j++)
                        if (dis[i][k]+dis[k][j]<dis[i][j])
                            dis[i][j]=dis[i][k]+dis[k][j];
        }
        printf("Case %d: %d\n",cas,m-ans);
    }
    return 0;
}
时间: 2024-11-18 00:28:14

[fzu 2271]不改变任意两点最短路至多删的边数的相关文章

任意两点最短路 Floyd-Warshall算法 传递闭包

Floyd-Warshall算法是求解任意两点最短路的有力武器.其也适用于存在负边的情况. DP思路,假设只使用前K个点时i到j的最短距离为d[k][i][j] 那么,使用前K+1个点就可以分成两种情况 ①i到j的最短路用到了第K+1个点(d[k+1][i][j] = d[k][i][j]) ②i到j的最短路没有用到第K+1个点(d[k+1][i][j] = d[k][i][k]+d[k][k][j]); 所以,d[k+1][i][j] = min(d[k][i][j],d[k][i][k]+d

Floyd-Warshall算法(求解任意两点间的最短路) 详解 + 变形 之 poj 2253 Frogger

/* 好久没有做有关图论的题了,复习一下. --------------------------------------------------------- 任意两点间的最短路(Floyd-Warshall算法) 动态规划: dp[k][i][j] := 节点i可以通过编号1,2...k的节点到达j节点的最短路径. 使用1,2...k的节点,可以分为以下两种情况来讨论: (1)i到j的最短路正好经过节点k一次 dp[k-1][i][k] + dp[k-1][k][j] (2)i到j的最短路完全

任意两点间的最短路 Floyd及其本质

我们知道在已知起点的情况下,求到其他任何一点的最短路是用dijkstra,那么在一个有向图中,我们想知道任意两点之间的最短路,我们就可以使用floyd,而且这个算法表面看起来非常的简单,就是一个三重循环,如果这个图有N个点,那么复杂度为O(|N|3),代码如下. 1 for(int k=0;k<n;k++) 2 for(int i=0;i<n;i++) 3 for(int j=0;j<n;j++) 4 d[i][j]=min(d[i][j],d[i][k]+d[k][j]); 在复杂度这

图论之最短路02-1——任意两点间最短距离及路径

======================================================== 求任意两点间最短距离及其路径.(万能最短路) 输入:权值矩阵,起点,终点 输出:最短距离矩阵,指定起讫点路径(经过的顶点编号) 为任意一点到其他点最短路奠定基础 ======================================================== function [P d]=liangdianzuiduanlu(W,qidian,zhongdian) W

图论之最短路02-2——改进的任意两点间最短距离及路径

======================================================== 重要程度 ***** 求任意两点间最短距离及其路径.(万能最短路) 输入:权值矩阵,起点,终点 输出:最短距离矩阵,指定起讫点路径(经过的顶点编号) ======================================================== function renyizuiduanlu(W) clc disp('                        

任意两点间的最短路问题 Floyd-Warshall算法

这一算法与之前的Bellman-F=Ford算法一样,都可以判断负环 只需要检查dp [i] [j] 是负数的顶点i即可 1 // 求解任意两点间的最短路径问题 2 // Floyed-Warshall算法 3 // 复杂度O(N^3),N为顶点数 4 5 #include <cstdio> 6 #include <iostream> 7 8 using namespace std; 9 // 用dp的思路来求解 10 // dp[k][i][j]:从i到j,只利用前K个节点的最短

基于pgrouting的任意两点间的最短路径查询函数二

在前面的博文中写过一篇查询任意两点间最短路径的函数,当时对pgrouting不熟悉,功能很low.现在对该函数进行扩展,支持用户自己输入查询的数据库表,这一点看似简单,其实意义很大,在做室内导航的时候当用户所在的楼层变化的时候最短路径函数查询的数据表名称也会发生变化,不可能一栋大楼里的道路都是一样的吧,另外进行跨楼层的最短路径规划时,需要查询从A到楼梯口的最短路径和楼梯口到B的最短路径,这些都需要进行最短路径规划的时候能够自己选择数据表. DROP FUNCTION pgr_fromAtoB(t

任意两点间最短距离floyd-warshall ---- POJ 2139 Six Degrees of Cowvin Bacon

floyd-warshall算法 通过dp思想 求任意两点之间最短距离 重复利用数组实现方式dist[i][j] i - j的最短距离 for(int k = 1; k <= N; k++) for (int i = 1; i <= N; i++) for (int j = 1; j <= N; j++) dist[i][j] = min(dist[i][j], dist[i][k]+dist[k][j]); 非常好实现 O(V^3) 这里贴一道刚好用到的题 http://poj.org

POJ No 2139 Six Degress of Cowvin Bacon(warshall_floyd(任意两点最短路径))

题目: http://poj.org/problem?id=2139 题解:N只牛,在一组的两只牛,分别两只之间为 “1度”,自己到自己为0度,M组牛.求,N只牛之中,两只牛之间 平均最短度数*100.模板Floyd算法,求任意两点之间最短路径. #include <iostream> #include <algorithm> #include <iomanip> using namespace std; const int maxn = 300 + 24; const