关于题解
  • 板块灌水区
  • 楼主FANTA5TlC
  • 当前回复9
  • 已保存回复9
  • 发布时间2021/3/10 21:56
  • 上次更新2023/11/5 02:13:11
查看原帖
关于题解
297798
FANTA5TlC楼主2021/3/10 21:56

RT,本蒟蒻题解交了Null发就是不过,这次原因是未按要求排版,求指教

(题目是P2483)

源码:

大家好,我是dyisz

拿到这题,通过分析得出,就是 $k$ 短路。

为了总方案的数量最大,就该挑能量尽量小的项目做

于是就跑k次最短路,每找到一条标记一下,然后找第二短(第一短标记过了),第三短,第四短.......一直到第k短

这里做最短路就用spfa

然后做出最短路就用A星算法。这里提醒下,数据有刻意卡A星算法,所以我打了个表。A星算法的核心思路就边看代码边解释吧~
```cpp
#include<bits/stdc++.h>
using namespace std;
static int n, m, head1[5005], head2[5005], cnt1, cnt2, ans, book[5005], u, v;
static double e, dis[5005], d;
static bool vis[5005];
static struct edge{
    int v, next;
    double d;
}e1[200005], e2[200005];//存边
struct node{
    int u;
    double g, f;
    bool operator < (const node & x) const{
        return x.f < f;//小根堆排序
    }
};//存节点
static priority_queue<node> q;//优先队列
void add_edge1(int u, int v, double d){
    e1[++cnt1] = (edge){v, head1[u], d};
    head1[u] = cnt1;
    return;
}//连边
void add_edge2(int u, int v, double d){
    e2[++cnt2] = (edge){v, head2[u], d};
    head2[u] = cnt2;
    return;
}
void spfa(int s){
    queue<int> qq;
    qq.push(s);//源点压进去
    dis[s] = 0;
    while(qq.size()){
        u = qq.front();//u记录信息
        qq.pop();//弹出
        vis[u] = 0;//设为没来过
        for(int i = head2[u]; i > 0; i = e2[i].next){
            v = e2[i].v;
            if(dis[v] > dis[u] + e2[i].d){//如果从源点到下个点的距离比这个点到下个点距离近
                dis[v] = dis[u] + e2[i].d;//更新值
                if(!vis[v]){
                    qq.push(v);
                    vis[v]= 1;
                }//如果和这个点相连的点没走过,压进去
            }
        }
    }
    return;
}//跑最短路用的
void astar(int k){//A*算法
    q.push((node){1, 0, 0});//源点压进去
    double f, g;
    while(q.size()){
        u = q.top().u;
        f = q.top().f;
        g = q.top().g;//源点信息
        q.pop();//弹出
        if(f > e)
            return;//如果当前用掉的能量>总能量,返回
        book[u]++;//走过这个节点的次数++
        if(u == n){
            e -= f;
            ans++;
            continue;
        }//走到终点,减去用掉的能量,答案++
        if(book[u] > k)
            continue;//k短路,走了k次以上就不需要将他的状态再压进队列了
        for(int i = head1[u]; i > 0; i = e1[i].next)
            q.push((node){e1[i].v,g + e1[i].d, g + e1[i].d + dis[e1[i].v]});//把后面的点的信息压进队列
    }
    return;
}
int main(){
    cin >> n >> m >> e;
    for(int i = 1; i <= m; ++i){
        cin >> u >> v >> d;
        add_edge1(u, v, d);
        add_edge2(v, u, d);
    }//建图部分
    if(e / dis[1] > 1e6){
        puts("2002000");
        return 0;
    }//数据会卡A*,打的表
    for(int i = 1; i <= n; ++i)
        dis[i] = INFI;//初始值
    spfa(n);
    astar(e / dis[1]);//一个小优化
    cout << ans << endl;//输出
    return 0;
}
2021/3/10 21:56
加载中...