![在这里插入图片描述](https://img-blog.csdnimg.cn/5b50c9496d644d5c95e2fd1c672f6aee.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAVmlrdG9yaWFl,size_20,color_FFFFFF,t_70,g_se,x_16)
- 题意 :给一有向图,删去图中某些边(可以不删),使剩下的边构成一颗树,且0号点到每个点的距离依然为原图中0号点到每个点的最短距离。求删边的方案数,即新图所有可能性的方案数。
- 思路 :先用dijkstra跑一遍0号点到所有点的最短路,考虑新图中的每一个点,能让它成立的方案数是其它最短路的点到它的路径满足是它的最短路径的个数。最后,由于是求总方案数,所以是每个点的方案数相乘。
- 注意这道题是用g中的距离为0表示无法到达,而不是0x3f,所以在初始化和输入的时候都完全不同!要判断是否有边
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 60;
const ll mod = 1e9 + 7;
int n;
int g[N][N];
int dist[N];
bool st[N];
ll cnt[N];
void dijkstra()
{
dist[0] = 0;
priority_queue<pii, vector<pii>, greater<pii>> heap;
heap.push({0, 0});
while (heap.size())
{
auto t = heap.top();
heap.pop();
int ver = t.second, distance = t.first;
if (st[ver]) continue;
st[ver] = true;
for (int i = 0; i < n; i ++ )
if (g[ver][i])
{
if (dist[i] > dist[ver] + g[ver][i])
{
dist[i] = dist[ver] + g[ver][i];
heap.push({dist[i], i});
}
}
}
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
while (cin >> n)
{
memset(dist, 0x3f, sizeof dist);
memset(cnt, 0, sizeof cnt);
memset(st, 0, sizeof st);
for (int i = 0; i < n; i ++ )
{
string line;
cin >> line;
for (int j = 0; j < n; j ++ )
g[i][j] = line[j] - '0';
}
dijkstra();
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
if (g[j][i] && dist[i] == dist[j] + g[j][i])
cnt[i] = (cnt[i] + 1) % mod;
ll ans = 1;
for (int i = 1; i < n; i ++ ) ans = ans * cnt[i] % mod;
cout << ans << endl;
}
return 0;
}