zoukankan      html  css  js  c++  java
  • P1841 [JSOI2007]重要的城市 最短路

      

    同样的情况也出现在城市间的交通中。某些城市如果出了问题,可能会引起其他很多城市的交通不便。另一些城市则影响不到别的城市的交通。jsoi冬令营的同学发现这是一个有趣的问题,于是决定研究这个问题。

    他们认为这样的城市是重要的:如果一个城市c被破坏后,存在两个不同的城市a和b(a, b均不等于c),a到b的最短距离增长了(或不通),则城市c是重要的。

    jsoi冬令营的同学面对着一张教练组交给他们的城市间交通图,他们希望能找出所有重要的城市。现在就请你来解决这个问题。

    输入输出格式

    输入格式:

    第一行两个整数N,M,N为城市数,M为道路数

    接下来M行,每行三个整数,表示两个城市之间的无向边,以及之间的路的长度

    输出格式:

    一行,按递增次序输出若干的数,表示重要的城市。

    输入输出样例

    输入样例#1: 复制
    4 4
    1 2 1
    2 3 1
    4 1 2
    4 3 2
    输出样例#1: 复制
    2

    如果去掉一个点 存在其他任意两个点的距离变大了 那么说明这是一个重要点 输出所有的重要点

    用floyed非常巧妙
    #include<iostream>
        #include<cstdio>
        #include<algorithm>
        #include<queue>
        using namespace std;
        const int INF=2e6;
        int e[205][205],city[205][205],m,n;
        bool ans[205],cs;
        int main()
        {
            cin>>n>>m;    
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    if(i!=j)
                        e[i][j]=INF;
            for(int i=1,x,y,u;i<=m;i++)
            {
                cin>>x>>y>>u;
                e[x][y]=e[y][x]=u;
            }
            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(i!=j&&j!=k)
                            {
                                if(e[i][j]>e[i][k]+e[k][j])
                                {
                                    e[i][j]=e[i][k]+e[k][j];
                                    city[i][j]=k;
                                }
                                else if(e[i][j]==e[i][k]+e[k][j])
                                    city[i][j]=-1;
                            }
            for(int i=1;i<=n;i++) 
                for(int j=1;j<=n;j++)
                    if(city[i][j]!=-1)
                        ans[city[i][j]]=true;    
            for(int i=1;i<=n;i++)
                if(ans[i])
                    cout<<i<<' ',cs=true;
            if(!cs)
                cout<<"No important cities.";
            return 0;
        }
    View Code

    还有一种用spfa枚举起点的方法:

    一个城市x重要,当且仅当去掉它之后可以让s->t的最短路变化(s != t != x)。因为本题的n很小,我们可以枚举n作为s。

    当确定s之后,以s为起点跑一次最短路,然后把所有在最短路上的边加入一个新图中。具体做法是:对于一条边,如果它起点处的最短路加上边权等于终点处的最短路,那么就把它加入新图中。

    这个新图有一个很好的性质:它是一个DAG。原因很简单,最短路上没环= =。注意到这个最短路DAG记录了s为起点到所有点的最短路。

    枚举1~n的每个点。如果存在边x->y,并且y的入度为1,那么删掉x之后y的入度会变成0,显然无法从s到达,即删掉x之后破坏了一些点的最短路。x就是一个关键点。(总而言之  找出所有的最短路  如果入度为1  那么from点就是重要城市)

    #include <bits/stdc++.h>
    using namespace std;
    
    inline int rd() {
        int a = 1, b = 0; char c = getchar();
        while (!isdigit(c)) a = c == '-' ? 0 : 1, c = getchar();
        while (isdigit(c)) b = b * 10 + c - '0', c = getchar();
        return a ? b : -b;
    }
    
    const int N = 500, M = N * N;
    struct Graph {
        int from, to, nxt, c;
    } g[M * 2];
    int head[N], tot;
    
    void addedge(int x, int y, int c) {
        g[++tot].to = y, g[tot].from = x, g[tot].c = c,
        g[tot].nxt = head[x], head[x] = tot;
    }
    
    int n, m;
    
    priority_queue<pair<int, int> > que;
    int dis[N], in[N];
    bool vis[N], important[N], mark[M];
    
    void solve(int s) {
        memset(dis, 0x3f, sizeof(dis));
        memset(vis, 0, sizeof(vis));
        dis[s] = 0;
        que.push(make_pair(0, s));
        while (!que.empty()) {
            int x = que.top().second;
            que.pop();
            if (!vis[x]) {
                vis[x] = true;
                for (int i = head[x]; i; i = g[i].nxt) {
                    int y = g[i].to;
                    if (dis[y] > dis[x] + g[i].c) {
                        dis[y] = dis[x] + g[i].c;
                        que.push(make_pair(-dis[y], y));
                    }
                }
            }
        }
    
        memset(mark, 0, sizeof(mark));
        memset(in, 0, sizeof(in));
        for (int i = 1; i <= tot; ++i) {
            if (dis[g[i].from] + g[i].c == dis[g[i].to]) {
                mark[i] = true;
                printf("from=%d v=%d to=%d
    ",g[i].from,g[i].c,g[i].to);
                ++in[g[i].to];
            }
        }
    
        for (int i = 1; i <= tot; ++i)
            if (mark[i] && in[g[i].to] == 1 && g[i].from != s)
                important[g[i].from] = true;
    }
    
    int main() {
        n = rd(), m = rd();
        for (int i = 1; i <= m; ++i) {
            int x = rd(), y = rd(), c = rd();
            addedge(x, y, c), addedge(y, x, c);
        }
    
            solve(1);
        bool ok = false;
        for (int i = 1; i <= n; ++i)
            if (important[i]) {
                cout << i << " ";
                ok = true;
            }
        if (!ok) cout << "No important cities.";
        cout << endl;
        return 0;
    }
    View Code





  • 相关阅读:
    cv2.SIFT() AttributeError: 'module' object has no attribute 'SIFT' OpenCV Python can't use SURF, SIFT
    CMake Error at cmake/OpenCVUtils.cmake
    安装opencv3.x卡在ICV: Downloading ippicv_linux_20151201.tgz...
    CMake Error at cmake/OpenCVModule.cmake:295 (message): No extra modules found in folder:Please provide path to 'opencv_contrib/modules' folder
    关于池化(pooling)理解!!!
    使用qt creator4.XXX,b编辑和调试caffe,太好用了
    Ubuntu下好的PDF阅读器介绍
    Qt的action控件中采用默认绑定,没有connect显示绑定!!!
    Ubuntu中更改所有子文件和子目录所有者权限
    关于ubuntu14.04,忘记root密码解决方案(经测试,内核3.13和4.2可行)。
  • 原文地址:https://www.cnblogs.com/bxd123/p/10963279.html
Copyright © 2011-2022 走看看