hdu 5361 In Touch 最短路(set+搜索实现)

题意:leader在1号位置,他要用最小的花费把他的命令通知到位。

   通知方式:每个人可以向离自己[L,R]的距离的人打电话(左右都可以),花费是C

   如题:他花费1可以通知第三四人,三又花费1通知第二个人,第五个人没办法收到

      所以通知五个人的最小花费分别是 0 2 1 1 -1


http://acm.hdu.edu.cn/showproblem.php?pid=5361


分析:

明显的最短路,但是边太多了,所以不能直接建边跑最短路。

用一个set存储所有的点,如果一个点有求得了最小花费,让这个点出set。

因为人固定了,他打电话的花费是固定的,所以可以用类似bfs的思想层次搜索。

第一个人能搜索的人入setF(setF按照花费从小到大排序),每次出set就是出的最小花费的点,根据此点继续进行搜索(在set里面二分找到可以搜的点),搜索到的点入setF。要知道根据这样的搜索方式,先搜索到的点一定已达到最小花费,所以改点直接出set,表示不会继续用它了。

       setF表示要搜索的点(代码中的f),set表示点集(搜完就可以出set了,代码中的st)。

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<set>
#define sf(n)    scanf("%d", &n)
#define MT(x,i)  memset(x,i,sizeof(x))
typedef long long LL;
using namespace std;
const int MAXN=2*100005;
struct node
{
    int id; LL dist;
    node(int id=-1,LL dist=-1):dist(dist),id(id) {}
    bool operator < (const node& rhs) const{ //这个重载< 必须要,让 搜索setF 按照花费从小到大
        if(dist==rhs.dist) return id<rhs.id;
        return dist<rhs.dist;
    }
};
set<node>f; set<int>st;
int L[MAXN],R[MAXN],C[MAXN]; LL ans[MAXN];
void add(int start,int en,node cur)
{
    set<int>::iterator s1=st.lower_bound(start);//二分找到可以开始的点
    for(; s1!=st.end()&&*s1<=en;){
        node y; y.id=*s1; st.erase(s1++); //出点集,以后不再用它
        ans[y.id]=cur.dist; //更新最小花费,每个点只会更新这一次
        y.dist=cur.dist+C[y.id]; //花费需要加上自己的花费
        f.insert(y); //改点入搜索set
    }
}
void solve()
{
    while(!f.empty()) {
        node cur=*f.begin();  f.erase(f.begin());//正在搜索的点

        int x=cur.id,start=x+L[x],en=x+R[x];
        add(start,en,cur);//搜索左边可以到达的点

        start=x-R[x],en=x-L[x];
        add(start,en,cur);//搜索右边可以到达的点
    }
}
int main()
{
    int T,n; sf(T);
    while(T--){
        sf(n);
        for(int i=0; i<n; i++)scanf("%d",&L[i]);
        for(int i=0; i<n; i++)scanf("%d",&R[i]);
        for(int i=0; i<n; i++)scanf("%d",&C[i]);
        f.clear(); st.clear();
        for(int i=1; i<n; i++) st.insert(i);
        f.insert(node(0,C[0]));//编号,距离
        MT(ans,-1); ans[0]=0;
        //以上初始化

        solve();
        for(int i=0; i<n; i++)
            printf("%I64d%s",ans[i],i==(n-1)?"\n":" ");
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值