• 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;
    }
  • 相关阅读:
    layui第三方组件运用
    layui select lay-filter就不渲染和全局渲染用法和校验
    layui 点击操作列后背景色去掉
    layui混合案列问题
    使用layui富文本添加日志内容,并获取子窗体的富文本内容
    layu tab切换table
    layui 父窗体传子窗体select动态选中
    jstl过长的内容处理空格以及换行并通过js处理内容自动换行
    js中运用jstl标签解决checked是否选中等问题
    javaMD5实现加密解密
  • 原文地址:https://www.cnblogs.com/Zinn/p/9326302.html
Copyright © 2020-2023  润新知