ICPCCamp2016day 1 - All Pair Shortest Path【bitset优化】

题意:给你一个n*n的01矩阵,代表一个有向图i到j是否连边,求所有i到j的最短路的平方和。

分析:由于边的长度的都为1,我们考虑bfs每次n^2可以求出i到其他点的最短路径,n^3求出答案,但是时间复杂度承受不了。

我们可以发现bfs时遍历了一个点后,其他的点都不用遍历它,我们可以用一个二进制数存下当前还没有遍历的点,bfs的时候我们只需要遍历当前点i要遍历的点&剩下的点。

时间复杂度n^3/64,这里要手写bitset实现。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 2005
#define Mm 2000005
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
int read() {
    char c;
    int ans=0,f=1;c=getchar();
    while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9') {ans=ans*10+c-'0';c=getchar();}
    return  ans*f;
}
int n;
ll e[Mn][Mn/61+1];
ll lowbit(ll x) {
    return x&(-x);
}
queue<int> q;
int dis[Mn][Mn];
ll bit[Mn/61+1];
void bfs(int st) {
    while(!q.empty()) q.pop();
    q.push(st);
    for(int i=0;i<=n/61;i++) bit[i]=(1LL<<61)-1;
    bit[(st-1)/61]-=(1LL<<(st-(st-1)/61*61-1));
    while(!q.empty()) {
        int u=q.front();
        q.pop();
        for(int i=0;i<=n/61;i++) {
            ll x=e[u][i]&bit[i];
            while(x>0) {
                ll y=lowbit(x);
                int v=(int)log2(y)+1+i*61;
                dis[st][v]=dis[st][u]+1;
                q.push(v);
                bit[i]-=y;
                x-=y;
            }
        }
    }
}
int main() {
    n=read();
    char s[Mn];
    for(int i=1;i<=n;i++) {
        scanf("%s",s);
        for(int j=1;j<=n;j++) {
            if(s[j-1]-'0'==1) {
                int k=(j-1)/61;
                e[i][k]|=(1LL<<(j-k*61-1));
            }
        }
    }
    ll sum=0;
    for(int i=1;i<=n;i++) {
        bfs(i);
        for(int j=1;j<=n;j++) {
            if(i==j) continue;
            if(dis[i][j]==0) dis[i][j]=n;
            sum+=dis[i][j]*dis[i][j];
        }
    }
    printf("%lld\n",sum);
    return 0;
}


你可能感兴趣的:(ICPCCamp2016day 1 - All Pair Shortest Path【bitset优化】)