同样的情况也出现在城市间的交通中。某些城市如果出了问题,可能会引起其他很多城市的交通不便。另一些城市则影响不到别的城市的交通。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: 复制
View Code
View Code
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; }
还有一种用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; }