zoukankan      html  css  js  c++  java
  • The Shortest Statement,题解

    题目链接

    分析:

      还是很明白的题意,直接分析问题,首先,这一题真的是给spfa用武之地,m比n大不超过20,但是这并不能使暴力不t,我们考虑一下如何改进一下,我们这样想,这个图只比它的生成树多最多21条边,而树上的最短路有是那么的容易(lca),我们可以先求出在树上两个点之间的最短路,可是非树边也很有可能通过啊,怎么办呢?我们可以这样想,通过至少一个非树边与只通过树边是对立的,也就是说除了只通过非树边的都通过树边,而只通过树边的很好求,下面我们来思考如何求通过至少一个非树边的路径。

      如果通过至少一个非树边,那么一定通过这个边的两个顶点那么就好办了,最多一共有42个顶点在非树边两边,直接枚举通过每一个就好了(当然要提前处理出这些顶点的单元最短路)。

      还有,这题spfa好像是比dij快(m-n<=20)。

    代码(dij)

    #include <cstdio>
    #include <queue>
    #include <cstring>
    using namespace std;
    const int maxn=1e5+10;
    struct E{
        int to;
        int next;
        long long val;
        int f;
        E(){
            f=0;
        }
    }ed[maxn*2];
    int head[maxn];
    int tot;
    void J(int a,int b,long long c){
        tot++;
        ed[tot].to=b;
        ed[tot].val=c;
        ed[tot].next=head[a];
        head[a]=tot;
    }
    int vis[maxn];
    int t[maxn][21];
    long long va[maxn][21];
    int js;
    int a[maxn];
    int b[maxn];
    long long c[maxn];
    int de[maxn];
    void Dfs(int x,int fa,int id){
        de[x]=de[fa]+1;
        t[x][0]=fa;
        va[x][0]=ed[id].val;
        for(int i=1;i<=20;i++){
            t[x][i]=t[t[x][i-1]][i-1];
            va[x][i]=va[x][i-1]+va[t[x][i-1]][i-1];
        }
        vis[x]=1;
        for(int i=head[x];i;i=ed[i].next){
            if(ed[i].to==fa||ed[i].f)
                continue;
            if(vis[ed[i].to]){
                ed[i].f=ed[i%2?(i+1):(i-1)].f=1;
                js++;
                a[js]=x;
                b[js]=ed[i].to;
                c[js]=ed[i].val;
                continue;
            }
            Dfs(ed[i].to,x,i);
        }
    }
    long long dis[43][maxn];
    int vis2[maxn];
    int ha;
    struct Node{
        int x;
        long long dis;
        Node(){
        }
        Node(int a,long long b){
            x=a;
            dis=b;
        }
        friend bool operator < (Node a,Node b){
            return a.dis>b.dis;
        }
    };
    priority_queue<Node> q;
    void dij(int s){
        memset(vis2,0,sizeof(vis2));
        ha++;
        dis[ha][s]=0;
        q.push(Node(s,0));
        while(!q.empty()){
            Node js=q.top();
            q.pop();
            if(vis2[js.x])
                continue;
            vis2[js.x]=1;
            for(int i=head[js.x];i;i=ed[i].next)
                if(dis[ha][ed[i].to]>dis[ha][js.x]+ed[i].val){
                    dis[ha][ed[i].to]=dis[ha][js.x]+ed[i].val;
                    q.push(Node(ed[i].to,dis[ha][ed[i].to]));
                }
        }
    }
    long long lca(int x,int y){
        long long ans=0;
        if(de[x]<de[y])
            swap(x,y);
        int k=de[x]-de[y];
        int ji=0;
        while(k){
            if(k&1){
                ans+=va[x][ji];
                x=t[x][ji];
            }
            k>>=1;
            ji++;
        }
        if(x==y)
            return ans;
        for(int i=20;i>=0;i--)
            if(t[x][i]!=t[y][i]){
                ans+=va[x][i];
                ans+=va[y][i];
                x=t[x][i];
                y=t[y][i];
            }
        ans+=va[x][0]+va[y][0];
        return ans;
    }
    long long Min(long long a,long long b){
        return a>b?b:a;
    }
    int main(){
        memset(dis,0x3f,sizeof(dis));
        int n,m;
        scanf("%d%d",&n,&m);
        int js1,js2;
        long long js3;
        for(int i=1;i<=m;i++){
            scanf("%d%d%lld",&js1,&js2,&js3);
            J(js1,js2,js3);
            J(js2,js1,js3);
        }
        Dfs(1,0,0);
        for(int i=1;i<=js;i++){
            dij(a[i]);
            dij(b[i]);
        }
        int q;
        scanf("%d",&q);
        for(int i=1;i<=q;i++){
            scanf("%d%d",&js1,&js2);
            long long p=lca(js1,js2);
            for(int j=1;j<=2*js;j++)
                p=Min(dis[j][js1]+dis[j][js2],p);
            printf("%lld
    ",p);
        }
        return 0;
    }
  • 相关阅读:
    windows C++ 获得一个进程的线程数目
    乌龟 SVN 在update后,如何知道 update前的版本号?
    C++ 类中的static对象貌似不能是类对象
    WinForms C#:html编辑器工程源码,含直接写WebBrowser的文件流、IPersistStreamInit接口的声明和一些相关的小方法
    用Remoting 实现一个文件传输组件
    [转载]Extreme Game Programming
    C#:10进制转2进制函数
    bindows 源码格式化工具(测试中的测试)C#源码
    明天又是周末,可以好好休息了!
    将文件加入到图形文件里;
  • 原文地址:https://www.cnblogs.com/wish-all-ac/p/12852632.html
Copyright © 2011-2022 走看看