题意:输入一个 01 矩阵表示的有向图,D(i,j)表示 i 到 j 的最短路中的长度,求所有 D(i,j)*D(i,j)的和。
思路:枚举每个点作为源点,从源点出发 bfs,记录到源点的距离。如果用 vis[]来记录点是否到达的话,那么将是一个 n^3 的复杂度。因此可以用 set 维护源点未到达的点,每次队首点从 set 中遍历。需要注意的是,遍历到不能马上删除,如果这个点在当前迭代处后面时程序会跪,所以记录下要删除的点,it 遍历一遍之后一起删除。
#include<iostream>
#include<cmath>
#include<queue>
#include<cstring>
#include<string>
#include<map>
#include<stack>
#include<set>
#include<cstdio>
#include<algorithm>
using namespace std;
int n;
char pic[1005][1005];
long long dis[1005];
long long bfs(int a){
memset(dis, -1, sizeof(dis));
queue<int> q;
set<int> s;
set<int>::iterator it;
dis[a] = 0;
for(int i = 0; i < n; i++){
if(i==a) continue;
if(pic[a][i] == '1'){
q.push(i);
dis[i] = 1;
}else
s.insert(i);
}
int del[1005];
int cnt = 0;
while(!q.empty() && !s.empty()){
int f = q.front();
q.pop();
for(it = s.begin(); it != s.end(); it++){
int p = *it;
if(pic[f][p] == '1'){
q.push(p);
dis[p] = dis[f]+1;
del[cnt++] = p;
}
}
for(int i = 0; i < cnt; i++)
s.erase(del[i]);
}
long long sum = 0;
for(int i = 0; i < n; i++){
if(dis[i] == -1) sum += n*n;
else sum += dis[i]*dis[i];
}
return sum;
}
int main(){
//freopen("a.txt", "r", stdin);
while(scanf("%d", &n) != EOF){
for(int i = 0; i < n; i++)
scanf("%s", pic[i]);
long long ans = 0;
for(int i = 0; i < n; i++){
ans += bfs(i);
}
cout << ans << endl;
}
return 0;
}