【USACO】Roadblock路障 解题报告

上午学校里组织测试碰到了这道题于是兴趣一起写了这篇Blog。
愉悦地在加长路径的时候加错了一条边,然而还是对了9个点……感叹自己的RP……果然经常%dalao还是有用的
这个题本身很明显就能看出是最短路问题,因为N≤250所以用迪杰斯特拉算法应该会更快一些,当然SPFA本身时间复杂度就低而且本题M≤25000也可以用。
为了防止玩脱加了个优先队列优化(堆优化)。用邻接表存储的图,但是给我在找路径的时候徒增了许多麻烦……因为这个题要求找出加草堆之后的最大差值,所以我们可以得出草堆只能加在原图点1–>N的最短路径上,否则的话对最短路没有影响。所以我存储下来最短路径,找出FJ所走的边后一个个乘2再跑一遍dij,这比直接一条条边乘2跑算法要优化不少。
因为是无向图,所以要开2*M的数组用来存边,正着反着各存一遍。
下面是我的代码。

#include<cstdio>
#include<queue>
using namespace std;
int u[50050],v[50050],w[50050],f[255],t[50050],cnt,d[255],n,m,rlt,rbt,pre[255];
struct E{
    int n,d;
}e;
bool operator <(E i,E j){//重载<号方便建堆(优先队列)优化
    return i.d>j.d?1:i.d==j.d?i.n>j.n?1:0:0;
}
priority_queue<E>q;
queue<int>road;//存储最短路径
void add(int U,int V,int W){cnt++;
    u[cnt]=U;v[cnt]=V;w[cnt]=W;
    t[cnt]=f[U],f[U]=cnt;
}//邻接表添加边
void reset(){int i,j;
    for(i=2;i<=n;i++)d[i]=0x3f3f3f3f;
    d[1]=0;
}//重置最短距离
int main(){int i,j,U,V,W,s,h;
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++){
        scanf("%d%d%d",&U,&V,&W);
        add(U,V,W),add(V,U,W);
    }reset();
    e.n=1;e.d=0;q.push(e);//堆优化dij
    while(!q.empty()){h=q.top().n;
        s=f[h],q.pop();
        while(s){
            if(d[v[s]]>d[h]+w[s]){
                d[v[s]]=d[h]+w[s];
                pre[v[s]]=h;
                e.n=v[s],e.d=d[v[s]];
                q.push(e);
            }s=t[s];
        }
    }rbt=d[n];s=n;//求出最短路径
    while(s){h=f[pre[s]];
        while(h){
            if(v[h]==s){
                road.push(h);
                break;
            }
            h=t[h];
        }s=pre[s];
    }
    while(!road.empty()){reset();//根据路径一个个路径修改求最大差值
        if(road.front()&1)
            w[road.front()+1]*=2,w[road.front()]*=2;
        else
            w[road.front()]*=2,w[road.front()-1]*=2;
        e.n=1;e.d=0;q.push(e);//依然是dij
        while(!q.empty()){h=q.top().n;
            s=f[h],q.pop();
            while(s){
                if(d[v[s]]>d[h]+w[s]){
                    d[v[s]]=d[h]+w[s];
                    e.n=v[s],e.d=d[v[s]];
                    q.push(e);
                }s=t[s];
            }
        }if(d[n]-rbt>rlt)rlt=d[n]-rbt;
        if(road.front()&1)
            w[road.front()]/=2,w[road.front()+1]/=2;
        else
            w[road.front()]/=2,w[road.front()-1]/=2;
        road.pop();
    }printf("%d",rlt);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值