【Bzoj4289】PA2012 Tax(Dijkstra+技巧建图)

Description

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

N<=100000

M<=200000

Solution

这题关键在于化边为点,把无向边拆成2条有向边

考虑最直白的一种建图方法,对于每一个点u,它的每一条入边向所有出边连边

但这样边数太多了,最坏是\(M^2\)条边,不可行

考虑用差值来建图,每条出边向第一条比它大的出边连一条权值为权差值的边,并且反向连一条权值为0的边

然后每条入边向对应的出边连一条为自身权值的边

设一个超级源点S和汇点T,S向1的所以出边连边,n的所以出边向T连边

这样边数是m级别的,然后跑最短路即可,

这题边数较多,我用spfa过不了,用Dijkstra堆优化可以过

Code

#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#define ll long long
#define Pa pair<ll,int>
using namespace std;

struct info{int to,nex,w;}e[400010],ne[2000010];
int n,m,tot=1,head[400010],nhead[400010],S,T;
ll dis[400010];
priority_queue<Pa,vector<Pa>,greater<Pa> > q;

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

inline void Link(int u,int v,int w){
    e[++tot].to=v;e[tot].w=w;e[tot].nex=head[u];head[u]=tot;
}

inline void nLink(int u,int v,int w){
    ne[++tot].to=v;ne[tot].w=w;ne[tot].nex=nhead[u];nhead[u]=tot;
}

bool cmp(int a,int b){return e[a].w<e[b].w;}
int tmp[400010],tp;
void Build(){
    tot=1;
    S=1,T=m*2+2;
    for(int i=1;i<=n;++i){
        tp=0;
        for(int j=head[i];j;j=e[j].nex) tmp[++tp]=j;
        sort(tmp+1,tmp+tp+1,cmp);
        for(int j=1;j<=tp;++j){
            int u=tmp[j],nex=tmp[j+1];
            if(e[u].to==n) nLink(u,T,e[u].w);
            if(i==1) nLink(S,u,e[u].w);
            nLink(u^1,u,e[u].w);
            if(j<tp) nLink(u,nex,e[nex].w-e[u].w),nLink(nex,u,0);
        }
    }
}

void Dijkstra(){
    for(int i=S;i<=T;++i)dis[i]=1ll<<60;
    q.push(make_pair(0,S));
    dis[S]=0;
    while(!q.empty()){
        int u=q.top().second;
        ll Dis=q.top().first;
        q.pop();
        if(Dis>dis[u]) continue;
        for(int i=nhead[u];i;i=ne[i].nex){
            int v=ne[i].to;
            if(dis[v]>dis[u]+ne[i].w){
                dis[v]=dis[u]+ne[i].w;
                q.push(make_pair(dis[v],v));
            }
        }
    }
}

int main(){
    n=read(),m=read();
    for(int i=1;i<=m;++i){
        int u=read(),v=read(),w=read();
        Link(u,v,w);
        Link(v,u,w);
    }
    Build();
    Dijkstra();
    printf("%lld\n",dis[T]);
    return 0;
}

原文地址:https://www.cnblogs.com/void-f/p/8537897.html

时间: 2024-08-05 11:15:18

【Bzoj4289】PA2012 Tax(Dijkstra+技巧建图)的相关文章

【BZOJ-4289】Tax 最短路 + 技巧建图

4289: PA2012 Tax Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 168  Solved: 69[Submit][Status][Discuss] Description 给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价.起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边权 N<=100000 M<=200000 Input Output Sample I

bzoj4289 PA2012 Tax——点边转化

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4289 好巧妙的转化!感觉自己难以想出来... 参考了博客:https://blog.csdn.net/reverie_mjp/article/details/52134142 把边变成点,相互之间连边: 原图上由一个点连接的许多边之间应该通过连新边达到题目要求的取较大值的目的: 做法就是把一个原图点的关联边排序,然后较小的边向较大的边连边权为差值的新边,较大的边连回去边权为0的新边: 那么

BZOJ4289 : PA2012 Tax

一个直观的想法是把每条边拆成两条有向边,同时每条有向边是新图中的一个点.对于两条边a->b与b->c,两点之间连有向边,费用为两条边费用的最大值.然后新建源点S与汇点T,由S向所有起点为1的边连边,T接受所有终点为n的边,那么答案就是S到T的最短路. 这样子的边数为$O(m^2)$,不能承受. 考虑枚举中转点x,将所有与它有关的边按费用从小到大排序.对于每条边,从以x为终点的点向以x为起点的点连边,费用为该边的费用.从以x为起点的点向下一条边连边,费用为两条边费用的差值,向上一条边连边,费用为

[UVA 10801]Lift Hopping[Dijkstra][建图]

题目链接:[UVA 10801]Lift Hopping[Dijkstra][建图] 题意分析: 从0层开始,一共有n台电梯供你到达目的地k层.每台电梯往上走一层都要消耗t[i]的时间,并且电梯只能在特定的楼层停下,换乘电梯要花费60s的时间,而且呢,你不能用楼梯上楼,只能搭电梯....(hentai!)问:最快到达楼层k的时间是多少?不能到达就输出-1. 解题思路: 这题技巧就是体现在建图上,图建好了,用dijkstra跑一遍就行了. 具体建图就是用mp[i][j]代表从楼层i到楼层j的最小距

ZOJ2750Idiomatic Phrases Game 建图Dijkstra

Dijkstra部分不难,主要是建图 #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<algorithm> #include<iostream> using namespace std; #define INF 10000000 #define maxn 1005 struct bian { string a; string

HDU 3036 Escape 网格图多人逃生 网络流||二分匹配 建图技巧

前言 在编程过程中总结归纳出来的一种编程经验,从而形成的设计思想称为设计模式. 设计模式有23种.它适用于所有的编程语言. 常用的有创新型的设计模式:简单工厂.抽象工厂和单例模式:行为型的设计模式:模板设计模式.观察者模式和命令模式:结构性的设计模式:适配器设计模式.代理模式(静态和动态两种,典型的有在spring的AOP编程中使用)和装饰器设计模式. 正文 单例模式(singleton) 保证一个类在内存中只能创建一个实例. 1.实现步骤: 1)将构造器私有化,即使用private修饰构造器

【bzoj3073】[Pa2011]Journeys 线段树优化建图+堆优化Dijkstra

题目描述 Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a,b),(c,d)表示,对于任意两个国家x,y,如果a<=x<=b,c<=y<=d,那么在xy之间建造一条道路.Seter保证不会有一个国家与自己之间有道路. Seter好不容易建好了所有道路,他现在在位于P号的首都.Seter想知道P号国家到任意一个国家最少需要经过几条道路.当然,Se

POJ 2502 Subway (Dijkstra 最短路+建图)

Subway Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6689   Accepted: 2176 Description You have just moved from a quiet Waterloo neighbourhood to a big, noisy city. Instead of getting to ride your bike to school every day, you now get

【PA2012】【BZOJ4289】Tax

Description 给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值.求从起点1到点N的最小代价. 起点的代价是离开起点的边的边权.终点的代价是进入终点的边的边权 N<=100000 M<=200000 Input Output Sample Input 4 5 1 2 5 1 3 2 2 3 1 2 4 4 3 4 8 Sample Output 12 HINT Source 一眼能看出是最短路变种.. 可是我仅仅会n^2建图T_T n^2建图就是边