2016 计蒜之道 复赛 A

来源:互联网 发布:淘宝教程视频完整版 编辑:程序博客网 时间:2024/04/30 10:00

  这场比赛对我来说最有价值就是这题。。读完题肯定会有一个朴素的想法,枚举不能使用的kn次floyd,也就是O(n4)的复杂度,无法通过。实际上,在跑那么多次floyd的时候,有很多操作是不必要的。所以可以分治来做,每次k只能取一半的值,剩下的递归处理,递归到k只有一个值没取,这样就避免了重复操作,优化到了O(n3log(n))

#include <bits/stdc++.h>using namespace std;#define ll long longconst int maxn = 305;int g[20][maxn][maxn];ll ans = 0;int n;void floyd(int l,int r,int dep){    if(l==r){        return;    }     if(l+1 == r){        for(int i=1;i<=n;i++){            for(int j=1;j<=n;j++){                if(i==l || j==l){                    continue;                }                ans += g[dep][i][j];            }        }        return;    }    int mid = (l+r)>>1;    //relex mid+1 r    memcpy(g[dep+1],g[dep],sizeof(g[dep]));    for(int k=mid;k<r;k++){        for(int i=1;i<=n;i++){            for(int j=1;j<=n;j++){                if(g[dep+1][i][k] == -1 || g[dep+1][k][j]==-1){                    continue;                }                if(g[dep+1][i][j] == -1){                    g[dep+1][i][j] = g[dep+1][i][k]+g[dep+1][k][j];                }                g[dep+1][i][j] = min(g[dep+1][i][j],g[dep+1][i][k]+g[dep+1][k][j]);            }        }    }    floyd(l,mid,dep+1);    //relex l mid-1    memcpy(g[dep+1],g[dep],sizeof(g[dep]));    for(int k=l;k<=mid-1;k++){        for(int i=1;i<=n;i++){            for(int j=1;j<=n;j++){                if(g[dep+1][i][k] == -1 || g[dep+1][k][j]==-1){                    continue;                }                if(g[dep+1][i][j] == -1){                    g[dep+1][i][j] = g[dep+1][i][k]+g[dep+1][k][j];                }                g[dep+1][i][j] = min(g[dep+1][i][j],g[dep+1][i][k]+g[dep+1][k][j]);            }        }    }    floyd(mid,r,dep+1);}int main(){    cin>>n;    for(int i=1;i<=n;i++){        for(int j=1;j<=n;j++){            scanf("%d",&g[0][i][j]);        }    }    floyd(1,n+1,0);    cout<<ans<<endl;    return 0;}
0 0
原创粉丝点击