链接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;
}