zoukankan      html  css  js  c++  java
  • 【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;
    }
  • 相关阅读:
    PAT B1027 打印沙漏 (20 分)
    PAT B1025 反转链表 (25 分)
    PAT B1022 D进制的A+B (20 分)
    PAT B1018 锤子剪刀布 (20 分)
    PAT B1017 A除以B (20 分)
    PAT B1015 德才论 (25 分)
    PAT B1013 数素数 (20 分)
    PAT B1010 一元多项式求导 (25 分)
    HDU 1405 The Last Practice
    HDU 1165 Eddy's research II
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/13387689.html
Copyright © 2011-2022 走看看