题目描述
参加jsoi冬令营的同学最近发现,由于南航校内修路截断了原来通向计算中心的路,导致去的路程比原先增加了近一公里。而食堂门前施工虽然也截断了原来通向计算中心的路,却没有使路程增加,因为可以找到同样长度的路作替代。其实,问题的关键在于,路截断的地方是交通要点。
同样的情况也出现在城市间的交通中。某些城市如果出了问题,可能会引起其他很多城市的交通不便。另一些城市则影响不到别的城市的交通。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
N<=200,M<=1e4
很显然的思路就是枚举每个点。然后 n^4 ,TLE。
怎么只跑一次floyd呢?就是floyd 的时候,记录最短路的个数。
然后对于我们当前枚举的点 k,如果存在:g[i][j]==g[i][k]+g[k][j]&&num[i][j]==num[i][k]*num[k][j] ,那么这个点对于i,j来说就是重要点。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=210;
int g[N][N],num[N][N],n,m,cnt;
void floyd(){
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
if(g[i][j]>g[i][k]+g[k][j]){
g[i][j]=g[i][k]+g[k][j];
num[i][j]=num[i][k]*num[k][j];
}else if(g[i][j]==g[i][k]+g[k][j]){
num[i][j]+=num[i][k]*num[k][j];
}
}
}
signed main(){
cin>>n>>m; memset(g,0x3f,sizeof g);
for(int i=1;i<=n;i++) g[i][i]=0;
for(int i=1,a,b,c;i<=m;i++){
cin>>a>>b>>c;
g[a][b]=g[b][a]=min(g[a][b],c);
num[a][b]=num[b][a]=1;
}
floyd();
for(int k=1;k<=n;k++){
int flag=0;
for(int i=1;i<=n&&!flag;i++){
for(int j=1;j<=n&&!flag;j++){
if(i==k||j==k) continue;
if(g[i][j]==g[i][k]+g[k][j]&&num[i][j]==num[i][k]*num[k][j])
flag=1;
}
}
if(flag) cnt++,cout<<k<<' ';
}
if(!cnt) puts("No important cities.");
return 0;
}
来源:CSDN
作者:青烟绕指柔!
链接:https://blog.csdn.net/weixin_43826249/article/details/104080894