码迷,mamicode.com
首页 > 其他好文 > 详细

The Shortest Statement,题解

时间:2020-05-08 19:52:43      阅读:68      评论:0      收藏:0      [点我收藏+]

标签:include   就是   main   --   com   ++   分析   The   friend   

题目链接

分析:

  还是很明白的题意,直接分析问题,首先,这一题真的是给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\n",p);
    }
    return 0;
}

 

The Shortest Statement,题解

标签:include   就是   main   --   com   ++   分析   The   friend   

原文地址:https://www.cnblogs.com/wish-all-ac/p/12852632.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!