• 【BZOJ4398】福慧双修 题解(建图优化)


    题目链接

    题目大意:给定一张$n$个点$m$条边的无向图,每条边两个方向的权值不一定相同。问从$1$出发不重复走一条边回到$1$的最短路径。

    -------------------

    暴力不太会。大概是$dfs$?复杂度不得上天……

    正解:对于那些端点不是$1$的边,因为要走最短路,所以这些边只会走一次,所以对答案是没有影响的。考虑端点为$1$的边,我们进行“二进制分组”。每次按照二进制分为两组:入边和出边,然后跑最短路。路径长为$dis[edge[i].to]$加上入边权值。这样做能把所有情况包括进去,符合最优性质。

    时间复杂度$O(nlog^2 n)$。

    代码:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    int n,m,vis[40005],dis[40005],tag[200005],ans=0x3f3f3f3f;
    int head[200005],cnt=-1;
    struct edge
    {
        int next,to,dis;
    }edge[200005];
    struct node
    {
        int dis,pos;
        bool operator < (const node &x) const
        {
            return x.dis<dis;
        }
    };
    priority_queue<node> q;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void add(int from,int to,int dis)
    {
        edge[++cnt].next=head[from];
        edge[cnt].to=to;
        edge[cnt].dis=dis;
        head[from]=cnt;
    } 
    inline void dijkstra()
    {
        for(int i=1;i<=n;i++) dis[i]=0x3f3f3f3f;
        memset(vis,0,sizeof(vis));
        dis[1]=0;q.push((node){0,1});
        while(!q.empty())
        {
            node tmp=q.top();q.pop();
            int now=tmp.pos;
            if (vis[now]) continue;
            vis[now]=1;
            for (int i=head[now];i!=-1;i=edge[i].next)
            {
                if (tag[i]==-1) continue;
                int to=edge[i].to;
                if (dis[to]>dis[now]+edge[i].dis)
                {
                    dis[to]=dis[now]+edge[i].dis;
                    if (!vis[to]) q.push((node){dis[to],to});
                }
            }
        }
        for (int i=head[1];i!=-1;i=edge[i].next)
            if (tag[i]==-1&&ans>dis[edge[i].to]+edge[i^1].dis)
                ans=dis[edge[i].to]+edge[i^1].dis;
    }
    signed main()
    {
        n=read(),m=read();
        memset(head,-1,sizeof(head));
        for (int i=1;i<=m;i++)
        {
            int u=read(),v=read(),w1=read(),w2=read();
            add(u,v,w1);add(v,u,w2);
        }
        for (int d=18;d>=0;d--)
        {
            for (int i=head[1];i!=-1;i=edge[i].next)
                if((i>>d)&1) tag[i]=0,tag[i^1]=-1;
                else tag[i]=-1,tag[i^1]=0;
            dijkstra();
            for (int i=head[1];i!=-1;i=edge[i].next)
                if ((i>>d)&1) tag[i]=-1,tag[i^1]=0;
                else tag[i]=0,tag[i^1]=-1;
            dijkstra();
        }
        printf("%lld",(ans==0x3f3f3f3f)?-1:ans);
        return 0;
    }
  • 相关阅读:
    启动 Eclipse 弹出“Failed to load the JNI shared library jvm.dll”错误的解决方法!
    Eclipse 出现Some sites could not be found. See the error log for more detail.错误 解决方法
    Android sdk manager不能更新下载缓慢的解决方法
    Android图像处理之Bitmap类
    FAQ_1_陌生的VERSION.SDK_INT
    Android5.0新特性——新增的Widget(Widget)
    Android5.0新特性——兼容性(support)
    springmvc通过ajax异步请求返回json格式数据
    redhat7学习笔记之从零到部署javaweb项目
    ssm框架实现图片上传显示并保存地址到数据库
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/13387689.html
Copyright © 2020-2023  润新知