BZOJ4289:PA2012 Tax-最短路-边化为点-难题

有任何问题欢迎留言或私聊

题目链接:BZOJ:4289: PA2012 Tax

题意:

给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大
值,求从起点1到点N的最小代价。起点的代价是离开起点的边的边权,终点的代价是进入终
点的边的边权
N<=100000
M<=200000

思路:

看了大神的博客之后,感觉大千世界,无(sang)奇(xin)不(bing)有(kuang)。
这个题的正确姿势是:

  1. 无向图连边时要拆成两条边
  2. 然后把边看成”点”,(优化:)因为不可能每个”点”之间都能连边,所以
  3. 对除了 1点和 n点之外的点连出去的边(真实边)按权值从小到大排个序,边看作”点”
  4. 然后 i “点”向 i + 1”点”连一条边值为(化点之前的两条边的权值差)i “点”向 i - 1”点”连一条权值为0LL的边;然后每个”点”和它反向边化成的”点”连一条边值为该边以前权值的边。
    5.然后用堆优化的dij跑一遍最短路,求出dis[i]( dis[i] = 初始点 到 i “点”的最短距离)
    6.最短路初始过程:将原点1连出去的 边看成点 后,加入队列。
    7.求值:枚举连向终点n的边,维护ans = minj{dis[i^1] + val[i]}// i 是边的编号

总结:

这题对于我来说很难,没碰到过这样无(sang)奇(xin)不(bing)有(kuang)的最短路。我真的菜啊!
这种将边看成点,然后奇妙连边构出新图的操作真的秀。

建议大家有机会自己试试这题,把代码搞懂之后,试着不看代码,自己一步步从头敲出来,然后再思考一发。
虽然现在a了这题,实话实说,一段时间过后,我肯定不能再a掉。但是思路应该是肯定了解的。码力还很差呀。加油把!

#include<bits/stdc++.h>
#define fuck(x) printf("*%d\n",(x))
using namespace std;
typedef long long LL;
typedef pair<LL, int> pii;
const int N = 1e5+5;
struct lh
{
    int to;
    LL val;
    int nex;
    lh(){}
    lh(int a,LL b,int c){to=a,val=b,nex=c;}
    friend bool operator<(const lh &a,const lh &b){
        return a.val<b.val;
    }
}cw[N*10],edge[N*10];
int head[N*5],vis[N*5];
LL dis[N*5];
std::vector<pii> g[N*5];
int n,m,tot;
void add(int x,int y,LL z){
    cw[++tot]=lh(y,z,head[x]);
    head[x]=tot;
    cw[++tot]=lh(x,z,head[y]);
    head[y]=tot;
}
void init(){
    memset(head,-1,sizeof(head));
    tot=-1;
    for(int i=0;i<5*N;++i)g[i].clear();
}
void dij(){
    priority_queue<pii,vector<pii> ,greater<pii> >Q;
    while(!Q.empty())Q.pop();
    memset(vis,0,sizeof(vis));
    memset(dis,0x3f,sizeof(dis));
    for(int i=head[1];~i;i=cw[i].nex){
        dis[i]=cw[i].val;
        //vis[i]=1;
        Q.push(make_pair(dis[i],i));
    }
    while(!Q.empty()){
        pii a=Q.top();Q.pop();
        int u=a.second;
        if(vis[u])continue;
        vis[u]=1;
        for(int i=g[u].size()-1;i>=0;--i){
            int v=g[u][i].second;
            if(vis[v])continue;
            if(dis[v]>dis[u]+g[u][i].first){
                dis[v]=dis[u]+g[u][i].first;
                Q.push(make_pair(dis[v],v));
            }
        }
    }
}
int main(int argc, char const *argv[])
{
    while(~scanf("%d%d",&n,&m)){
        init();
        int x,y;
        LL z;
        for(int i=0;i<m;++i){
            scanf("%d%d%lld",&x,&y,&z);
            add(x,y,z);
        }
        for(int ii=2,tp=0;ii<n;tp=0,++ii){ 
            for(int e=head[ii];~e;e=cw[e].nex){
                edge[++tp].to=e;edge[tp].val=cw[e].val;
            }
            sort(edge+1,edge+1+tp);
            for(int i=1;i<=tp;++i){
                if(i!=1)g[edge[i].to].push_back(make_pair(0LL,edge[i-1].to));
                if(i!=tp)g[edge[i].to].push_back(make_pair(edge[i+1].val-edge[i].val,edge[i+1].to));
                g[edge[i].to^1].push_back(make_pair(edge[i].val,edge[i].to));
            }
        }
        dij();
        LL ans=0x3f3f3f3f3f3f3f3f;
        for(int i=head[n];~i;i=cw[i].nex){
            ans=min(ans,dis[i^1]+cw[i].val);
        }
        printf("%lld\n",ans );
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39599067/article/details/80139374
今日推荐