BZOJ.4289.PA2012 Tax(思路 Dijkstra)

题目链接

\(Description\)

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

\(Solution\)

最直接的方法是把每条边作为一个点,对于连接同一个点的两条边连一条新边,最后把连接1和n的点分别连S、T,跑最短路
但这样边数是O(m^2)的
对于路径上相邻两条边\((i,j,v1)\)和\((j,k,v2)\),v1<v2,考虑如何构图把v1比v2小的部分补上
那么对于点j拆点,每个点对应一条出边或入边,按边权排序,设相邻两点对应权值为v1,v2(v1<v2),那么建边\((j',j,0)\),\((j,j',v2-v1)\)
最后起点处的代价没有被计算,在起点的每条出边加上一个点即可
复杂度O(mlogm)
很像的边表边很容易写错。。
不会写代码。。
没有边权范围要longlong

//35772kb  1892ms
#include <queue>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
//#define gc() getchar()
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
#define pr std::pair<LL,int>
#define mp std::make_pair
typedef long long LL;
const int N=4e5+5,M=4e5+5,MAXIN=3e6;//N:两倍边数
const LL INF=1ll<<60;

int src,des,n,m,Enum,H[N],nxt[M<<2],to[M<<2],val[M<<2],tmp[M];//边数一直错。。mdzz 开始一共4e5条边
int num,h[N>>1],tto[M],tnxt[M],tval[M];
LL dis[N];
bool vis[N];
char IN[MAXIN],*SS=IN,*TT=IN;
std::priority_queue<pr> q;

inline int read()
{
    int now=0,f=1;register char c=gc();
    for(;!isdigit(c);c=gc()) if(c=='-') f=-1;
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now*f;
}
inline bool cmp(int i,int j) {return tval[i]<tval[j];}
inline void Add(int u,int v,int w){
    tto[++num]=v, tnxt[num]=h[u], tval[num]=w, h[u]=num;
}
inline void AddEdge(int u,int v,int w){
    to[++Enum]=v, nxt[Enum]=H[u], val[Enum]=w, H[u]=Enum;
}
void Build()
{
    src=1, des=(m+1)<<1;
    for(int i=1; i<=n; ++i)
    {
        int cnt=0;
        for(int j=h[i]; j; j=tnxt[j])
            tmp[++cnt]=j;//存编号就行了
        std::sort(tmp+1,tmp+1+cnt,cmp);
        for(int now,next,j=1; j<=cnt; ++j)//~
        {
            now=tmp[j], next=tmp[j+1];//直接拿边号来建就可以了 也是建的双向边
            if(i==1) AddEdge(src,now,tval[now]);//把连向src的边拆出一个点来
            if(tto[now]==n) AddEdge(now,des,tval[now]);
            AddEdge(now^1,now,tval[now]);//只建一条边 还有另一个点的边
            if(j<cnt) AddEdge(now,next,tval[next]-tval[now]), AddEdge(next,now,0);
        }
//      if(cnt) AddEdge(tmp[cnt]^1,tmp[cnt],tval[tmp[cnt]]);//WA!没有上面两个条件特判!
    }
}
LL Dijkstra()
{
    for(int i=src+1; i<=des; ++i) dis[i]=INF;
    dis[src]=0, q.push(mp(0,src));
    while(!q.empty())
    {
        int x=q.top().second; q.pop();
        if(vis[x]) continue;
        if(x==des) return dis[x];
        vis[x]=1;
        for(int v,i=H[x]; i; i=nxt[i])
            if(!vis[v=to[i]] && dis[v]>dis[x]+val[i])
                dis[v]=dis[x]+val[i], q.push(mp(-dis[v],v));
    }
    return dis[des];
}

int main()
{
    n=read(),m=read();
    num=1;
    for(int u,v,w,i=1; i<=m; ++i)
        u=read(),v=read(),w=read(),Add(u,v,w),Add(v,u,w);
    Build();
    printf("%lld",Dijkstra());

    return 0;
}

原文地址:https://www.cnblogs.com/SovietPower/p/8463637.html

时间: 2024-10-10 18:03:34

BZOJ.4289.PA2012 Tax(思路 Dijkstra)的相关文章

●BZOJ 4289 PA2012 Tax

●赘述题目 算了,题目没有重复的必要. 注意理解:对答案造成贡献的是每个点,就是了. 举个栗子: 对于如下数据: 2 1 1 2 1 答案是 2: ●题解 方法:建图(难点)+最短路. 先来几个链接:(他们为我解题提供了思路,但有些部分看得我有点mengbi) ●http://blog.csdn.net/pure_w/article/details/55060079 ●http://www.cnblogs.com/clrs97/p/5046933.html 建图: 1.把原图的双向边拆成两条单向

BZOJ 4289: PA2012 Tax

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

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

Description 给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价.起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边权 N<=100000 M<=200000 Solution 这题关键在于化边为点,把无向边拆成2条有向边 考虑最直白的一种建图方法,对于每一个点u,它的每一条入边向所有出边连边 但这样边数太多了,最坏是\(M^2\)条边,不可行 考虑用差值来建图,每条出边向第一条比它大的出边连一条权值为权差值的

bzoj 4289 Tax - 最短路

题目传送门 这是一条通往vjudge的神秘通道 这是一条通往bzoj的神秘通道 题目大意 如果一条路径走过的边依次为$e_{1}, e_{2}, \cdots , e_{k}$,那么它的长度为$e_{1} + \max (e_{1}, e_{2}) + \max (e_{2}, e_{3}) + \cdots + \max (e_{k - 1}, e_{k}) + e_{k}$,问点$1$到点$n$的最短路. 显然需要把状态记在最后一条边上. 然后给一个菊花图,这个做法就gg了. 因此考虑一些黑

bzoj 4289 TAX —— 点边转化

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4289 把边转化成点,同一个原有点相连的边中,边权小的向大的连差值的边,大的向小的连0的边: 一开始想的是给每个新点记一个点权是这个点(边)原来的权,走到它时先加上点权,因为要在原图上经过这条边还是要花费边权: 但是这样在原图中的边之间转移时会把它们的边权都加上,就不对了: 所以应该是把原图的边进一步拆成两个点,两端点的集合各加入一个,这两点之间连原边权的边: 题目上什么也没说...总之 d

bzoj4289 PA2012 Tax——点边转化

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

[PA2012] Tax

传送门:>Here< 题意:给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价.起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边权N<=100000 M<=200000 解题思路 不免要吐槽一下这题的数据,久调一下午无果与标程对拍没有任何差错不知道为什么就是WA 既然极限数据已经和标程拍上了那么权当出了吧…… 不过还是一道好题 首先考虑这道题暴力的做法——将每条边作为新图的点,然后枚举原图的点,遍历一遍这个

Bzoj 2834: 回家的路 dijkstra,堆优化,分层图,最短路

2834: 回家的路 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 62  Solved: 38[Submit][Status][Discuss] Description Input Output Sample Input 2 1 1 2 1 1 2 2 Sample Output 5 HINT N<=20000,M<=100000 Source dijkstra+堆优化+分层图 把所有的横向和纵向分开看.跑最短路即可. 注意:N这么大,不能写

BZOJ 3040: 最短路(road) [Dijkstra + pb_ds]

3040: 最短路(road) Time Limit: 60 Sec  Memory Limit: 200 MBSubmit: 2476  Solved: 814[Submit][Status][Discuss] Description N个点,M条边的有向图,求点1到点N的最短路(保证存在).1<=N<=1000000,1<=M<=10000000 Input 第一行两个整数N.M,表示点数和边数.第二行六个整数T.rxa.rxc.rya.ryc.rp. 前T条边采用如下方式生成