题目:
https://cn.vjudge.net/problem/CodeForces-208C
大意:
有n个城市,编号为1-n,有m条双向路,现要在一个点设立警察局,通过这个点的路就是安全路,求1到n的每条最短路上平均的安全路的条数,即安全路总可能条数/总最短路条数。
思路:
题目比较难理解,吃了英语的亏,首先是安全路总可能条数,在点2-n-1中某个点x建警察局,则在每条最短路中会产生2条安全路,在x点建立警察局所产生的总条数就是1到x的路径*x到n的路径;总最短路条数便是1到n的所有最短路条数,于是可以用spfa计算最短路,dp记录条数。另外要注意最短路和条数要使用long long,否则会载在Test 22,因为假设六个一组形成16个4叉路,剩下四个再形成三叉路,则总最短路条数为2^32*3,大于int范围。(思路比较难理解,建议边看代码边理解)。
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<map>
#include<queue>
#include<vector>
#include<set>;
using namespace std;
typedef __int64 ll;
const int inf = 0x3f3f3f;
vector<int> m[105];
ll dis[105], dp[105];
int n, num;
void spfa(int st) {
for(int i = 1; i <= n; i++) {
dp[i] = 0;
dis[i] = inf;
}
dis[st] = 0;
dp[st] = 1;
queue<int> q;
q.push(st);
while(!q.empty()) {
int now = q.front();
q.pop();
for(int i = 0; i < m[now].size(); i++) {
int to = m[now][i];
if(dis[to] > dis[now]+1) {
dis[to] = dis[now] + 1;
dp[to] = dp[now];
q.push(to);
}
else if(dis[to] == dis[now] + 1) dp[to] += dp[now];
}
}
}
int main() {
//freopen("in.txt","r",stdin);
int a, b;
scanf("%d%d",&n,&num);
for(int i = 0; i < num; i++) {
cin >> a >> b;
m[a].push_back(b);
m[b].push_back(a);
}
spfa(1);
ll len = dis[n], sum = dp[n];
double ans = 1.0;
for(int i = 2; i < n; i++) {
spfa(i);
if(dis[1]+dis[n] == len) ans = max(ans,2.0*dp[1]*dp[n]/(double)sum);
}
printf("%.12lf",ans);
return 0;
}