• BZOJ 2069 POI2004 ZAW 堆优化Dijkstra


    题目大意:给定一张无向图。每条边从两个方向走各有一个权值,求从点1往出走至少一步之后回到点1且不经过一条边多次的最短路
    显然我们须要从点1出发走到某个和点1相邻的点上,然后沿最短路走到还有一个和点1相邻的点上,然后回到点1
    那么我们将与点1相邻的点都设为关键点。然后将点1从图中删除。题目转化成了给定图上的一些关键点求近期点对
    枚举每一个点显然会T
    考虑每次将关键点划分为两个集合A,B。然后将A中的每一个点x的初始距离设为len(1,x),跑最短路,然后用B中的每一个点ydisy+len(y,1)统计答案,再将AB反转做一次
    这样仅仅要随意点对都被分别划分到两个集合中至少一次,那么答案就被更新完了
    怎样划分呢?我们考虑依照二进制拆分,对于每一位划分一次,将该位上为0的划分到A集合中。该位上为1的划分到B集合中
    因为两个数至少有一位不同,因此随意点对至少被划分了一次
    这样划分O(log2n)次就够了

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define M 5050
    using namespace std;
    struct abcd{
        int to,f,next;
    }table[M<<2];
    int head[M],tot;
    int n,m,top,ans=0x3f3f3f3f;
    pair<int,pair<int,int> >stack[M<<1];
    int f[M];
    void Add(int x,int y,int z)
    {
        table[++tot].to=y;
        table[tot].f=z;
        table[tot].next=head[x];
        head[x]=tot;
    }
    namespace Heap{
        int heap[M],pos[M],top;
        void Push_Up(int t)
        {
            while(t>1)
            {
                if( f[heap[t]]<f[heap[t>>1]] )
                    swap(heap[t],heap[t>>1]),swap(pos[heap[t]],pos[heap[t>>1]]),t>>=1;
                else
                    break;
            }
        }
        void Insert(int x)
        {
            heap[++top]=x;
            pos[x]=top;
            Push_Up(top);
        }
        void Pop()
        {
            pos[heap[1]]=0;
            heap[1]=heap[top--];
            if(top) pos[heap[1]]=1;
            int t=2;
            while(t<=top)
            {
                if( f[heap[t+1]]<f[heap[t]] )
                    ++t;
                if( f[heap[t]]<f[heap[t>>1]] )
                    swap(heap[t],heap[t>>1]),swap(pos[heap[t]],pos[heap[t>>1]]),t<<=1;
                else
                    break;
            }
        }
    }
    void Dijkstra()
    {
        using namespace Heap;
        int i;
        for(i=1;i<=n;i++)
            Insert(i);
        while(Heap::top)
        {
            int x=heap[1];Pop();
            for(i=head[x];i;i=table[i].next)
                if(f[table[i].to]>f[x]+table[i].f)
                {
                    f[table[i].to]=f[x]+table[i].f;
                    Push_Up(pos[table[i].to]);
                }
        }
    }
    int main()
    {
        int i,j,x,y,z1,z2;
        cin>>n>>m;
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d%d",&x,&y,&z1,&z2);
            if(x>y) swap(x,y),swap(z1,z2);
            if(x==1)
                stack[++top]=make_pair(y,make_pair(z1,z2));
            else
                Add(x,y,z1),Add(y,x,z2);
        }
        for(j=1;j<=n;j<<=1)
        {
            memset(f,0x3f,sizeof f);
            for(i=1;i<=top;i++)
                if(i&j)
                    f[stack[i].first]=stack[i].second.first;
            Dijkstra();
            for(i=1;i<=top;i++)
                if(~i&j)
                    ans=min(ans,f[stack[i].first]+stack[i].second.second);
    
            memset(f,0x3f,sizeof f);
            for(i=1;i<=top;i++)
                if(~i&j)
                    f[stack[i].first]=stack[i].second.first;
            Dijkstra();
            for(i=1;i<=top;i++)
                if(i&j)
                    ans=min(ans,f[stack[i].first]+stack[i].second.second);
        }
        cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    设计模式之单例模式
    EditText的光标在4.0中的bug
    省赛热身赛之Median
    VB6获取本机所有IP地址公用函数
    省赛热身赛之Kagome Kagome
    OpenCV学习笔记(30)KAZE 算法原理与源码分析(四)KAZE特征的性能分析与比较
    使用jQuery validate 验证注册表单
    Oracle 发布 GlassFish 路线图
    Oracle 发布 GlassFish 路线图
    Java 中的双重检查(DoubleCheck)
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/7257408.html
Copyright © 2020-2023  润新知