• P3008 [USACO11JAN]道路和飞机Roads and Planes


    传送门

    肯定是最短路

    而且题目有限制,不存在负环

    所以可以跑堆优化的Dijkstra

    但是因为有负边权,所以跑得很慢

    这时可以利用题目的条件

    每个联通块内是没有负边权的

    所以可以优先处理单个块之内的最短路

    这样一个块一个块地处理

    可以跑得很快

    可以用Tarjan处理每个点所在的联通块

    代码:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    using namespace std;
    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<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x*f;
    }
    
    const int N=1e6+7;
    int n,r,p,sta;
    int fir[25007],from[N],to[N],val[N],cnt;//存边
    inline void add(int &a,int &b,int &c)
    {
        from[++cnt]=fir[a];
        fir[a]=cnt; to[cnt]=b; val[cnt]=c;
    }
    //int fa[25007];
    //inline int find(int &x){ return x==fa[x] ? x : fa[x]=find(fa[x]); }
    
    //Tarjan模板
    int dfs_clock,cnt2,_top,low[25002],dfn[25002],be[25002],st[25002];
    inline void Tarjan(int x)
    {
        dfn[x]=low[x]=++dfs_clock; st[++_top]=x;
        for(int i=fir[x];i;i=from[i])
        {
            int v=to[i];
            if(!dfn[v]) Tarjan(v),low[x]=min(low[x],low[v]);
            else if(!be[v]) low[x]=min(low[x],dfn[v]);
        }
        if(low[x]==dfn[x])
        {
            be[x]=++cnt2;
            while(st[_top]!=x) be[st[_top--]]=cnt2;
            --_top;
        }
    }
    
    int dis[25007];
    struct node
    {
        int pos,v;
        bool operator < (const node &b) const{
            return fa[pos]!=fa[b.pos] ? fa[pos]<fa[b.pos] : v>b.v ;//优先处理同一个块内的点
        }
    };
    priority_queue <node> q;
    void Dijk()
    {
        int pos,v;
        memset(dis,0x7f,sizeof(dis));
        q.push((node){sta,0}); dis[sta]=0;
        while(!q.empty())
        {
            node u=q.top(); q.pop();
            if(u.v!=dis[u.pos]) continue;
            for(int i=fir[u.pos];i;i=from[i])
            {
                pos=to[i],v=u.v+val[i];
                if(dis[pos]>v)
                {
                    dis[pos]=v;
                    q.push((node){pos,v});
                }
            }
        }
    }
    
    int main()
    {
        int a,b,c,xa,xb;
        cin>>n>>r>>p>>sta;
        //for(int i=1;i<=n;i++) fa[i]=i;
        for(int i=1;i<=r;i++)
        {
            a=read(); b=read(); c=read();
            add(a,b,c); add(b,a,c);
            //xa=find(a); xb=find(b);
            //if(xa!=xb) fa[xa]=xb;
        }
        //for(int i=1;i<=n;i++) find(i);
    
        for(int i=1;i<=p;i++)
        {
            a=read(); b=read(); c=read();
            add(a,b,c);
        }
    
        for(int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i);
        Dijk();
    
        for(int i=1;i<=n;i++)
        {
            if(dis[i]==dis[0]) printf("NO PATH
    ");
            else printf("%d
    ",dis[i]);
        }
        return 0;
    }

    后话:

    这题一开始我处理同一块用的是并查集

    但是不知道为什么就是没用,根本不能加速

    总是T两个点

    然后心态爆炸

    直接把CRK大佬的Tarjan模板复制过来了

    然后把处理联通块的步骤放到读入飞机航线之前(感觉没毛病吧,反正航线又不会形成强联通分量)

    速度跟并查集一样...

    把Tarjan放到读入航线后就过了....

    总觉得数据有毒....

  • 相关阅读:
    电子表单系列谈之纯文本辅助设计表单
    论欧喷索斯应当缓行
    一种用户体验显示对话框时灰化你的主窗体
    程序源代码行数分析统计器
    电子表单系列谈之电子表单基础概念
    通过WebService来使用报表
    使用VBA扩展VS.NET集成开发环境,有Flash演示动画
    Ajax , 好大一颗地雷啊
    发布CHM文档生成器 可替代 HTML Help Workshop,有全部C#源代码
    使用VBA.NET压缩备份C#工程
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9699002.html
Copyright © 2020-2023  润新知