链接http://www.codeforces.com/problemset/problem/208/C
题意:给你一幅图,每条边边权为1,要求你在某个位置建一个警察局,使得从1到n的所有最短路中与这个警察局有接触的边的条数最多
ps:
假如一条路径经过警察局,那么肯定会经过两条与警察局有关的边(起点、终点除外)
解法:
先对图求点对间的最短路,处理出新图,在新图中,所有从s到t的路径都是最短路径,然后利用拓扑排序得到的拓扑序(也可以广搜)处理出s到某个点共有几条路(简单DP)。
(在反图中)反过来再重复一遍
in[i]表示从s到i的总路径数,out[i]表示从t到i的总路径数
那么in[i]*out[i]就是经过i的总路径数
#include<cstdio> #include<cstring> #include<queue> #include<vector> #include<algorithm> using namespace std; void Max(double &a,double b){if(b>a) a=b;} const int inf = ~0u>>2; int mp[105][105]; int n,m; struct { int a,b; }edge[10010]; vector<int> Edge[101],fedge[101]; int c[110]; int topo[110]; int T; bool dfs(int u){ c[u]=-1; for(int i=0;i<Edge[u].size();i++){ int v=Edge[u][i]; if(c[v]<0) return false; else if(!c[v] && !dfs(v)) return false; } c[u]=1; topo[--T]=u; return true; } void topsort(int n){ T=n+1; memset(c,0,sizeof(c)); dfs(1); } double in[110],out[110]; int main(){ while(scanf("%d%d",&n,&m)!=EOF){ for(int i=0;i<=n;i++) Edge[i].clear(); fill(mp[0],mp[101],inf); for(int i=1;i<=n;i++) mp[i][i]=0; int a,b; for(int i=1;i<=m;i++){ scanf("%d%d",&a,&b); edge[i].a=a; edge[i].b=b; mp[a][b]=mp[b][a]=1; } for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) if(mp[i][k]+mp[k][j]<mp[i][j]) mp[i][j]=mp[i][k]+mp[k][j]; memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); for(int i=1;i<=m;i++){ int a=edge[i].a,b=edge[i].b; if(mp[1][a]+mp[a][b]+mp[b][n]==mp[1][n]){ Edge[a].push_back(b); fedge[b].push_back(a); } if(mp[1][b]+mp[b][a]+mp[a][n]==mp[1][n]){ Edge[b].push_back(a); fedge[a].push_back(b); } } topsort(n); for(int i=T;i<=n;i++){ int s=topo[i]; if(!in[s]) in[s]=1; for(int j=0;j<Edge[s].size();j++){ int t=Edge[s][j]; in[t]+=in[s]; } } for(int i=n;i>=T;i--){ int s=topo[i]; if(!out[s]) out[s]=1; for(int j=0;j<fedge[s].size();j++){ int t=fedge[s][j]; out[t]+=out[s]; } } double t=in[n]; double ans=0; for(int i=1;i<=n;i++) { double tmp=(in[i]*out[i]); if(i!=1 && i!=n) tmp*=2; Max(ans,tmp/t); } printf("%lf\n",ans); } return 0; }