CDOJ 1287 MC挖矿世界(Spfa+set优化)

题目大意:原题链接

解题思路:此题要求多点最短距离,但是直接套用floyd会超时.

然后我们想直接从每一个点开始bfs就好了,但是还是会TLE,为什么呢?

因为你访问了很多次没有意义的地方,因为有些点你曾经访问过,但是在你遍历边集的时候,你还去访问他,这个行为就会很多余。

所以我们用set来优化一下.

这个均摊下来,复杂度大概是n^2*logn的

最蛋疼的情况是你每次最多更新sqrt(n)个点,你需要更新sqrt(n)次,每次遍历和更新的复杂度都是logn,大概是这样……

输入             输入

3                 2

010             10

001             01

100             输出

输出             8

15               先介绍一下set的一些基本操作:参考链接

insert(key)              和vector中push_back()作用相同

erase(key)               删除键值key的值

erase(iterator)        删除定位器iterator指向的值

erase(first,second) 删除定位器first和second之间(左闭右开)的值

注意:

1.set中的数据是自动去重的;

2.it指向set的某个数,如果set这个数被erase,it的指针会变;

#include<set>
#include<queue>
#include<string>
#include<iostream>
using namespace std;
set<int> S;
int n,d[2010];
string g[2010];
queue<int> que;
long long ans=0;

void Spfa(int x)
{
    S.clear();
    while(!que.empty()) que.pop();
    for(int i=0;i<n;i++) d[i]=n;
    for(int i=0;i<n;i++){ 
        if(i!=x) 
            S.insert(i);
    } 
    d[x]=0,que.push(x); 
    while(!que.empty()){
        int u=que.front();
        que.pop();
        set<int>::iterator it=S.begin();//每次必须重新定义,因为set集合S每次都在变化
        while(S.size()&&it!=S.end()){
            int v=*it;
            if(g[u][v]=='1'){
                d[v]=d[u]+1;
                it++;//it++位置很重要 
                que.push(v);
                S.erase(v);
            }
            else it++;
        }
    }
    for(int i=0;i<n;i++)
        ans+=d[i]*d[i];
}

int main()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>g[i];
    for(int i=0;i<n;i++) Spfa(i);
    cout<<ans<<endl;
} 

 

posted @ 2017-03-03 19:58  despair_ghost  阅读(267)  评论(0编辑  收藏  举报