题意:给出一个图,要求删除一些边,然后使得删除后的图是一颗树,并且各个点到0点的距离为原来图中的最短距离,求有多少种删法
最短路求出根到每个点的距离,然后遍历每一个点,找到满足最短路的关键路径数:d[i] + cost[i][j] == d[j]
将所有这些值相乘即可得到。
链接:hdu 6026
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
using namespace std;
const int maxn = 50 + 10;
const int inf = 1e9 + 7;
int n;
int cost[maxn][maxn];
int d[maxn], inq[maxn];
void spfa(int s) //改进的spfaq
{
memset(inq, 0, sizeof(inq));
memset(d, inf, sizeof(d));
queue<int> q;
d[s] = 0;
inq[s] = 1;
q.push(s);
while(!q.empty()) {
int u = q.front();
q.pop();
inq[u] = 0;
for(int i = 0; i < n; i++) {
if(d[i] > d[u] + cost[u][i]) {
d[i] = d[u] + cost[u][i];
if(inq[i]) continue;
inq[i] = 1;
q.push(i);
}
}
}
}
int main()
{
while(~scanf("%d", &n)) {
string str;
for(int i = 0; i < n; i++) {
cin >> str;
for(int j = i + 1; j < n; j++) {
if(str[j] - '0' == 0) {
cost[i][j] = cost[j][i] = inf;
}
else {
cost[i][j] = cost[j][i] = str[j] - '0';
}
}
}
spfa(0);
/*for(int i = 0; i < n; i++) {
cout << d[i] << " ";
}
cout << endl;*/
long long ans = 1;
for(int j = 1; j < n; j++) {
long long res = 0;
for(int i = 0; i < n; i++) {
if(i == j) {
continue;
}
if(cost[i][j] == inf) continue;
if(d[i] + cost[i][j] == d[j]) {
res++;
}
}
if(res != 0) ans = (ans * res) % inf;
}
cout << ans << endl;
}
return 0;
}