zoukankan      html  css  js  c++  java
  • bzoj4289 PA2012 Tax——点边转化

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4289

    好巧妙的转化!感觉自己难以想出来...

    参考了博客:https://blog.csdn.net/reverie_mjp/article/details/52134142

    把边变成点,相互之间连边;

    原图上由一个点连接的许多边之间应该通过连新边达到题目要求的取较大值的目的;

    做法就是把一个原图点的关联边排序,然后较小的边向较大的边连边权为差值的新边,较大的边连回去边权为0的新边;

    那么如果原图上要走 a,b 两条边,新图上两条边(点)之间有代价,付出代价等价于取较大值;

    还要注意原图是无向图,连新边时要连向自己的反向边,因为新图连的都是有向边,所以这样可以实现原图中走一条边移动的效果,也就是两个原图点的关联边之间也有联系;

    再建立一个源点和汇点,1号点的关联边都连向源点,连向 n 号点的边都连向汇点;

    然后从源点开始跑最短路,到汇点的最短路就是答案。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    int const maxn=1e5+5,maxm=4e5+5;
    int n,m,head[maxn],xt=1,hd[maxm],ct=1,tmp[maxm],t,S,T;
    ll dis[maxm];
    bool vis[maxm];
    priority_queue<pair<ll,int> >q;//ll!!!
    struct N{
        int to,nxt,w;
        N(int t=0,int n=0,int w=0):to(t),nxt(n),w(w) {}
    }ed[maxm<<3],edge[maxm];
    void add1(int x,int y,int w){edge[++xt]=N(y,head[x],w); head[x]=xt;}
    void add2(int x,int y,int w){ed[++ct]=N(y,hd[x],w); hd[x]=ct;}
    bool cmp(int x,int y){return edge[x].w<edge[y].w;}
    void dijkstra()
    {
        memset(dis,0x3f,sizeof dis);
        dis[S]=0; q.push(make_pair(0,S)); 
        while(q.size())
        {
            int x=q.top().second; q.pop();
            if(vis[x])continue;
            vis[x]=1;
            for(int i=hd[x],u;i;i=ed[i].nxt)
            {
                if(dis[u=ed[i].to]>dis[x]+ed[i].w)
                {
                    dis[u]=dis[x]+ed[i].w;
                    q.push(make_pair(-dis[u],u));
                }
            }
        }
        
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1,x,y,z;i<=m;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            add1(x,y,z); add1(y,x,z);
        }
        S=1; T=2*(m+1);
        for(int i=1;i<=n;i++)
        {
            t=0;
            for(int j=head[i];j;j=edge[j].nxt)tmp[++t]=j;
            sort(tmp+1,tmp+t+1,cmp);
            for(int j=1;j<=t;j++)
            {
                if(i==1)add2(S,tmp[j],edge[tmp[j]].w);
                if(edge[tmp[j]].to==n)add2(tmp[j],T,edge[tmp[j]].w);
                add2(tmp[j]^1,tmp[j],edge[tmp[j]].w);//!
                if(j<t)
                {
                    add2(tmp[j],tmp[j+1],edge[tmp[j+1]].w-edge[tmp[j]].w);
                    add2(tmp[j+1],tmp[j],0);
                }
            }
        }
        dijkstra();
        printf("%lld
    ",dis[T]);
        return 0;
    }
  • 相关阅读:
    数据类型装换
    变量及数据类型
    27 网络通信协议 udp tcp
    26 socket简单操作
    26 socket简单操作
    14 内置函数 递归 二分法查找
    15 装饰器 开闭原则 代参装饰器 多个装饰器同一函数应用
    12 生成器和生成器函数以及各种推导式
    13 内置函数 匿名函数 eval,exec,compile
    10 函数进阶 动态传参 作用域和名称空间 函数的嵌套 全局变量
  • 原文地址:https://www.cnblogs.com/Zinn/p/9326302.html
Copyright © 2011-2022 走看看