輝夜's profileKaguya Houraisan's glori...PhotosBlogListsMore Tools Help

Blog


    June, 2008

    USACO 3.2.6 Sweet Butter 题解 (续)

    上一篇在这里
     
    虽然SPFA已经得出了比较满意的结果,但现在又发现了优化算法,这样一来SPFA就把Dijkstra甩开了一大截。
    下面直接引用我在上一篇的留言:
    对于APSP问题如果用单源最短路径算法的话,曾考虑过用先求出的最短路径优化,使得在后面求新源点的最短路径时对已求过的点之间可以一次优化到最终结果避免多次进入队列更新,这个优化对SPFA算法尤其明显。不过这样一来就需要用邻接矩阵储存边,对稀疏图来说需要空间比较多,也可以看成是一种DP的思想吧(空间换时间)。虽然最短路存在了邻接矩阵中,但对稀疏图计算时还是用邻接表算,这个效率依然是最高的(实践验证过,用时相差10倍以上)。
     
    今天实践了一下,发现具体实现和开始想的优化方法还有些不同:只能在求过的点中取一点进行优化(多了效果不升反降)

    #include<fstream>
    #include<vector>
    #include<list>
    #include<queue>
    using namespace std;
     
    const int infinite=1000000000;
    int nCow,nPasture,nConnect;
    vector<int> vCowsAt;
    vector< list< pair<int,int> > > vPasAjt;
    vector< vector<int> > vDistMatrix;
     
    inline bool relax(int u, int v, int weight, vector<int> &d){
        int newlength=d[u]+weight;
        if(newlength<d[v]){
            d[v]=newlength;
            return true;
        }
        return false;
    }
     
    int CalPathSum(int iSource){
        queue<int> Q;
        vector<bool> IsInQ(nPasture);
     
    // optimizing begin:
        if(iSource>0){
            int iShort=0;
            for(int k=1;k<iSource;++k)if(vDistMatrix[k][iSource]<vDistMatrix[iShort][iSource])
                iShort=k;
            for(int iDes=0;iDes<nPasture;++iDes)
                vDistMatrix[iSource][iDes]=vDistMatrix[iShort][iSource]+vDistMatrix[iShort][iDes];
        }
    // optimizing end.
     
        vDistMatrix[iSource][iSource]=0;
        Q.push(iSource);
        IsInQ[iSource]=true;
        while(!Q.empty()){
            int u=Q.front();
            Q.pop();
            IsInQ[u]=false;
            for(list< pair<int,int> >::iterator itr=vPasAjt[u].begin();itr!=vPasAjt[u].end();++itr){
                int v=itr->first;
                if(relax(u,v,itr->second,vDistMatrix[iSource]) && !IsInQ[v]){
                    Q.push(v);
                    IsInQ[v]=true;
                }
            }
        }
     
        int sum=0;
        for(int i=0;i<nCow;++i)sum+=vDistMatrix[iSource][vCowsAt[i]];
        return sum;
    }
     
    int main(){
        ifstream fin("butter.in");
        ofstream fout("butter.out");

        fin>>nCow>>nPasture>>nConnect;
        vCowsAt.resize(nCow);
        vPasAjt.resize(nPasture);
        vDistMatrix.resize(nPasture);

        for(int i=0;i<nPasture;++i)
            vDistMatrix[i].resize(nPasture,infinite);
        for(int i=0;i<nCow;++i){
            int iPasture;
            fin>>iPasture;
            vCowsAt[i]=iPasture-1;
        }
        for(int i=0;i<nConnect;++i){
            int u,v,distance;
            fin>>u>>v>>distance;
            vPasAjt[u-1].push_back(pair<int,int>(v-1,distance));
            vPasAjt[v-1].push_back(pair<int,int>(u-1,distance));
        }
     
        int minpath=infinite;
        for(int i=0;i<nPasture;++i)
            minpath=min(minpath,CalPathSum(i));
        fout<<minpath<<endl;
    }
    程序变化不大,只是多了对 vDistMatrix 矩阵的处理,并加上了优化部分(已标出)。由于使用了动态空间分配,内存占用没有想象的增加那么多。
    下面是运行结果:

    TASK: butter
    LANG: C++
     
    Compiling...
    Compile: OK
     
    Executing...
       Test 1: TEST OK [0.022 secs, 2852 KB]
       Test 2: TEST OK [0.000 secs, 2856 KB]
       Test 3: TEST OK [0.000 secs, 2856 KB]
       Test 4: TEST OK [0.000 secs, 2852 KB]
       Test 5: TEST OK [0.011 secs, 2856 KB]
       Test 6: TEST OK [0.011 secs, 2988 KB]
       Test 7: TEST OK [0.043 secs, 3512 KB]
       Test 8: TEST OK [0.065 secs, 4308 KB]
       Test 9: TEST OK [0.086 secs, 5364 KB]
       Test 10: TEST OK [0.108 secs, 5360 KB]
     
    All tests OK.
    时间几乎缩短了一半,可惜最后一个测试点差点突破 0.1secs ...

    Comments (4)

    Please wait...
    Sorry, the comment you entered is too long. Please shorten it.
    You didn't enter anything. Please try again.
    Sorry, we can't add your comment right now. Please try again later.
    To add a comment, you need permission from your parent. Ask for permission
    Your parent has turned off comments.
    Sorry, we can't delete your comment right now. Please try again later.
    You've exceeded the maximum number of comments that can be left in one day. Please try again in 24 hours.
    Your account has had the ability to leave comments disabled because our systems indicate that you may be spamming other users. If you believe that your account has been disabled in error please contact Windows Live support.
    Complete the security check below to finish leaving your comment.
    The characters you type in the security check must match the characters in the picture or audio.

    To add a comment, sign in with your Windows Live ID (if you use Hotmail, Messenger, or Xbox LIVE, you have a Windows Live ID). Sign in


    Don't have a Windows Live ID? Sign up

    [To:tony]
    呵呵,这题的优化不是像你想象的那样只对已求出的点做优化,实际上是对所有点的优化(包括到未求出的点,但使用了已求过的点到这些点的最短距离。)考虑到 SPFA 的过程,你的方法实际上应该作用不大。这个优化貌似有点不好理解,这几天有时间的话可以专门写一篇
    然后关于链式前向星,我稍微搜索了一下,貌似就是一个二维不定长数组的一维实现形式。但由于变成了一维,就有一个明显缺点是每个向量的维数已定,无法再动态改变,对咱现在已经习惯了二维动态数组的来说貌似意义不大呵呵。看下 C++ 标准库的 vector 就知道了,相当好用且高效。
    Oct. 23
    tonywrote:
    还有针对空间问题,我不知道链式前向星这种数据结构对你有没有帮助。我用的语言是pascal,我看c+就很别扭。所以没看你的具体实现。
    Oct. 21
    tonywrote:
    不太清楚这个题你说的优化,对于求第i个点,1~i-1点到点i的最短路以求出,为了防止不更新,我是用以求出的最短路长度+1来初始化i到已知最短路边的值。这个样子行么?MS差的不少。
    Test 10: TEST OK [0.194 secs, 1480 KB]
    Oct. 21
    子 王wrote:
    继续继续沙发....
     
    继续继续飘过....^^
    June 2

    Trackbacks

    The trackback URL for this entry is:
    http://dantvt.spaces.live.com/blog/cns!D87988A6CAC0A480!775.trak
    Weblogs that reference this entry
    • None