【链接】
http://acm.hdu.edu.cn/showproblem.php?pid=6026
【题意】
给定一个无向图,删去几条边,得到n个节点的最短路树,求有几种可能性
【思路】
求删边的方法,也就是求树的构造 方法树的构造方法=每条边的选择方法累乘。
弗洛伊德求出每点之间的最短路,计数0-i的每个数的最短路数,相乘即可。
【代码】
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 105;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
char s[maxn][maxn];
int dis[maxn][maxn];
int cnt[maxn];
int n;
void folyd() {
for (int k = 0; k < n; k++) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
dis[i][j] %= mod;
}
}
}
}
int main() {
while (~scanf("%d", &n)) {
memset(cnt, 0, sizeof(cnt));
for (int i = 0; i < n; i++) {
scanf("%s", s[i]);
for (int j = 0; j < n; j++) {
if (i == j)dis[i][j] = 0;
else if (s[i][j] == '0') {
dis[i][j] = inf;
}
else {
dis[i][j] = s[i][j] - '0';
}
}
}
folyd();
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (s[i][j] == '0')continue;
if (dis[0][i] + s[i][j] - '0' == dis[0][j]) {
cnt[j]++;
}
}
}
ll ans = 1;
for (int i = 1; i < n; i++) {
ans *= cnt[i];
ans %= mod;
}
printf("%lld\n", ans);
}
}