题目描述
n个城市用m条双向公路连接,使得任意两个城市都能直接或间接地连通。其中城市编号为1..n,公路编号为1..m。任意个两个城市间的货物运输会选择最短路径,把这n*(n-1)条最短路径的和记为S。现在你来寻找关键公路r,公路r必须满足:当r堵塞之后,S的值会变大(如果r堵塞后使得城市u和v不可达,则S为无穷大)。
输入格式
第1行包含两个整数n,m,接下来的m行,每行用三个整数描述一条公路a,b,len(1<=a,b<=n),表示城市a和城市b之间的公路长度为len,这些公路依次编号为1..m。
n<=100,1<=m<=3000,1<=len<=10000。
输出格式
从小到大输出关键公路的编号。
先考虑暴力。
显然,对于一个点u,如果删去的边不在它到其它点的最短路上,那么S是不会变的。考虑到两点之间的最短路不止一条,我们可以给每个点先建出一棵最短路径树出来,然后枚举最短路径树上的每条边并把它删掉,再跑一遍最短路,看S是否变大即可。如果最短路用dijkstra+heap来做,这个过程的时间复杂度就是:
[O(N*((N+M)log(N+M)+N*(N+M)log(N+M)))
]
也就N^3logN的级别。可以过这题。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#define maxn 101
#define maxm 3001
using namespace std;
vector<int> to[maxn],w[maxn],id[maxn];
int dis[maxn],treeid[maxn];
bool vis[maxn],lzs[maxm];
int n,m;
inline int read(){
register int x(0),f(1); register char c(getchar());
while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
inline void dijkstra(const int &s,const int &del){
priority_queue< pair<int,int>,vector< pair<int,int> >,greater< pair<int,int> > > q;
memset(vis,false,sizeof vis),memset(dis,0x3f,sizeof dis);
q.push(make_pair(0,s)),dis[s]=0;
while(q.size()){
int u=q.top().second; q.pop();
if(vis[u]) continue; vis[u]=true;
for(register int i=0;i<to[u].size();i++) if(id[u][i]!=del){
int v=to[u][i];
if(dis[v]>dis[u]+w[u][i]){
dis[v]=dis[u]+w[u][i],q.push(make_pair(dis[v],v));
if(!del) treeid[v]=id[u][i];
}
}
}
}
inline void out(int a){
if(a>=10)out(a/10);
putchar(a%10+'0');
}
int main(){
n=read(),m=read();
memset(dis,0x3f,sizeof dis);
for(register int i=1;i<=m;i++){
int u=read(),v=read(),_w=read();
to[u].push_back(v),w[u].push_back(_w),id[u].push_back(i);
to[v].push_back(u),w[v].push_back(_w),id[v].push_back(i);
}
for(register int i=1;i<=n;i++){
dijkstra(i,0);
int sum=0; for(register int j=1;j<=n;j++) sum+=dis[j];
for(register int j=1;j<=n;j++) if(treeid[j]&&!lzs[treeid[j]]){
dijkstra(i,treeid[j]);
int cnt=0; for(register int k=1;k<=n;k++) cnt+=dis[k];
if(cnt>sum) lzs[treeid[j]]=true;
}
}
bool flag=false;
for(register int i=1;i<=m;i++) if(lzs[i]){
out(i),putchar('
');
}
return 0;
}