考虑“删除后图仍连通”,即其不是无向图的桥(bridge),可以用Tarjan算法预处理,这里不赘述。
【算法一】
枚举删除的是哪条边,然后枚举起点,暴搜,统计答案。
可以通过0、1号测试点。
预计得分:20分。
【算法二】
枚举删除的是哪条边,接着,
①枚举起点,∵op=0,∴裸最短路,Heap-dijkstra/SPFA。时间复杂度: O(m2*n*logn)/O(m2*n*k)。
②Floyd,时间复杂度O(m*n3)。
可以通过0、1、2、3号测试点。
预计得分:40分。
【算法三】
枚举删的是哪条边,接着,枚举终点,逆着推回去,考虑op=1的边,则有w[U][V]=(dis[U]+18)/19。然后跑Heap-dijkstra/SPFA即可。
时间复杂度:O(m2*n*logn)/O(m2*n*k)。
可以通过0、1、2、3、4、5号测试点。
预计得分:60分。
【算法四】
考虑删除某条边E后,以某个点U为终点的最短路是否发生变化。
我们发现,在某个无向图中,以U为根节点,到其他所有点的最短路构成了一棵树,即“最短路树(shortest-path tree)”。我们删除的边如果不在最短路树上,对当前图中的以U为起点的所有最短路不发生变化。
我们可以在Heap-dijkstra/SPFA的同时处理出最短路树:
if(dis[V]>dis[U]+w[U][V]) TreeEdge[S][V]=Edge[U][V];
//TreeEdge[S][V]表示以S为起点的单源最短路树中,V结点的父边。
于是算法得出:
首先枚举终点,然后枚举删除的边,仅仅需要重复求删除n-1条在最短路树上的边的答案即可,其他的边可以直接用之前预处理的答案就好了。
时间复杂度:O(n2*m*logn)/O(n2*k*m)。Heap-dijkstra可能需要卡常数。
预计得分:100分。
#include<cstdio> #include<algorithm> #include<cstring> #include<queue> using namespace std; #define N 111 #define M 1101 queue<int>q; int dis[N],ans,ans2[M<<1],sumv[N],need[N]; int n,m,first[N],next[M<<1],v[M<<1],en,TEs[N][N]/*树边*/,x,y,es[N][N]; bool w[M<<1]/*道路类型*/,z,Del[M<<1]/*当前删除的边*/,ontree[N][M<<1] /*ontree[i][j]表示边j是否在以i为汇点的最短路树上*/,inq[N]; void AddEdge(const int &U,const int &V,const bool &W) { v[en]=V; w[en]=W; next[en]=first[U]; first[U]=en; es[U][V]=en++; } int calc(const int &U,const bool &op){return op ? (dis[U]+18)/19 : 1;} void spfa(const int &s,const bool &op) { memset(dis,0x7f,sizeof(dis)); memset(inq,0,sizeof(inq)); dis[s]=need[s]; inq[s]=1; q.push(s); while(!q.empty()) { int U=q.front(); for(int i=first[U];i!=-1;i=next[i]) if(!Del[i]) { int C=calc(U,w[i]); if(dis[v[i]]>dis[U]+C) { if(!op) TEs[s][v[i]]=es[U][v[i]]; dis[v[i]]=dis[U]+C; if(!inq[v[i]]) q.push(v[i]),inq[v[i]]=1; } } q.pop(); inq[U]=0; } if(!op) { for(int i=1;i<=n;++i) sumv[s]+=dis[i]; ans+=sumv[s]; for(int i=1;i<=n;++i) if(i!=s) ontree[s][TEs[s][i]]=ontree[s][TEs[s][i]^1]=1; } } int dfn[N],dep; bool bridge[M<<1]; int Tarjan(int U,int fa) { int lowU=dfn[U]=++dep; for(int i=first[U];i!=-1;i=next[i]) if(!dfn[v[i]]) { int lowV=Tarjan(v[i],U); lowU=min(lowU,lowV); if(lowV>dfn[U]) bridge[i]=bridge[i^1]=1; } else if(v[i]!=fa) lowU=min(lowU,dfn[v[i]]); return lowU; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) scanf("%d",&need[i]); memset(first,-1,sizeof(first)); for(int i=1;i<=m;++i) { scanf("%d%d%d",&x,&y,&z); AddEdge(x,y,z); AddEdge(y,x,z); } Tarjan(1,0); for(int i=1;i<=n;++i) spfa(i,0); for(int i=1;i<=n;++i) { for(int j=1;j<=n;++j) if((!bridge[TEs[i][j]])&&(j!=i)) { Del[TEs[i][j]]=Del[TEs[i][j]^1]=1; spfa(i,1); Del[TEs[i][j]]=Del[TEs[i][j]^1]=0; int tmp=ans2[TEs[i][j]]; for(int k=1;k<=n;++k) ans2[TEs[i][j]]+=dis[k]; ans2[TEs[i][j]^1]+=(ans2[TEs[i][j]]-tmp); } for(int j=0;j<en;++j) if((!bridge[j])&&(!ontree[i][j])) ans2[j]+=sumv[i]; } printf("%d %d\n",ans,*max_element(ans2,ans2+en)); return 0; }