[SCOI2007]k短路

题目描述

n n 个城市和 m 条单向道路,城市编号为 1 1 n 。每条道路连接两个不同的城市,且任意两条道路要么起点不同要么终点不同,因此 n n m 满足 mn(n1) m ≤ n ( n − 1 )

给定两个城市ab,可以给ab的所有简单路(所有城市最多经过一次,包括起点和终点)排序:先按长度从小到大排序,长度相同时按照字典序从小到大排序。你的任务是求出ab的第 k k 短路

输入输出格式

输入格式:

输入第一行包含五个正整数n, m, k, a, b。

以下m行每行三个整数u, v, l,表示从城市u到城市v有一条长度为l的单向道路。

输出格式:

如果a到b的简单路不足k条,输出No,否则输出第k短路:从城市a开始依次输出每个到达的城市,直到城市b,中间用减号"-"分割。

输入输出样例

输入样例#1: 复制
5 20 10 1 5
1 2 1
1 3 2
1 4 1
1 5 3
2 1 1
2 3 1
2 4 2
2 5 2
3 1 1
3 2 2
3 4 1
3 5 1
4 1 1
4 2 1
4 3 1
4 5 2
5 1 1
5 2 1
5 3 1
5 4 1
输出样例#1: 复制
1-2-4-3-5

输入样例#2: 复制
4 6 1 1 4
2 4 2
1 3 2
1 2 1
1 4 3
2 3 1
3 4 1
输出样例#2: 复制
1-2-3-4

输入样例#3: 复制
3 3 5 1 3
1 2 1
2 3 1
1 3 1
输出样例#3: 复制
No

说明

第一个例子有5个城市,所有可能出现的道路均存在。从城市1到城市5一共有5条简单路,排序如下:

20%的数据满足:n<=5

40%的数据满足:n<=30

100%的数据满足:2<=n<=50, 1<=k<=200

A*做法

带有估价函数的优先队列BFS称为A*算法。只要保证对于任意状态state,都有f(state)g(state),A*算法就一定能在目标状态第一次从堆中被取出时得到最优解,并且在搜索过程中每个状态只需要被扩展一次(之后再取出可以直接忽略)。估价函数 f(state) f ( s t a t e ) 越准确、越接近 g(state) g ( s t a t e ) ,A*算法的效率就越高。如果估价始终为0,就等价于普通的优先队列BFS。

#include<bits/stdc++.h>
#define gc getchar
#define ll long long
inline ll read(){ll x = 0; char ch = gc(); bool positive = 1;for (; !isdigit(ch); 
ch = gc()) if (ch == '-')  positive = 0;for (; isdigit(ch); ch = gc())  x = x * 10 
+ ch - '0';return positive ? x : -x;}inline void write(ll a){if(a>=10)write(a/10);
putchar('0'+a%10);}inline void writeln(ll a){if(a<0){a=-a; putchar('-');}write(a);
puts("");}

using namespace std;
const int N = 60, M = 3700;
int n, m, s, t, k;
struct G{
    int en, ver[M], nxt[M], head[N], w[M];
    inline void add(int x, int y, int z) {
        ver[++en] = y;
        w[en] = z;
        nxt[en] = head[x];
        head[x] = en;
    }
}pos,neg;
bool inq[N];
int d[N];
void spfa() {
    memset(d, 0x3f, sizeof d);
    d[t] = 0;
    queue<int>q;
    q.push(t);
    while(!q.empty()) {
        int x = q.front(); q.pop();
        inq[x] = false;
        for(int i = neg.head[x]; i; i = neg.nxt[i]) {
            int y = neg.ver[i];
            if(d[y] > d[x] + neg.w[i]) {
                d[y] = d[x] + neg.w[i];
                if(!inq[y]) inq[y] = true, q.push(y);
            }
        }
    }
}
struct Node{
    int u,f, g;
    bool v[N];
    vector<int>path;
    bool operator<(const Node & rhs) const {
        return f + g > rhs.f + rhs.g || f + g == rhs.f + rhs.g && path > rhs.path;
    }
    bool judge(int x) {
        return !v[x];
    }
    inline void insert(int x) {
        v[x] = true;
    }
}now, cur;
priority_queue<Node>q;
void bfs(){
    now.u = s;
    now.f = d[s];
    now.path.push_back(s);
    now.v[s] = true;
    q.push(now);
    int cnt = 0;
    while(!q.empty()) {
        now = q.top(); q.pop();
        if(now.u == t) {
            ++cnt;  
            if(cnt == k) {
                for(int i = 0; i  < now.path.size(); ++i) {
                    if(i) putchar('-');
                    write(now.path[i]);
                }
                return;
            }
        } else {
            int x = now.u;
            for(int i = pos.head[x]; i; i = pos.nxt[i]) {
                int y = pos.ver[i];
                if(now.judge(y)) {
                    cur = now;
                    cur.g += pos.w[i];
                    cur.f = d[y];
                    cur.insert(y);
                    cur.u = y;
                    cur.path.push_back(y);
                    q.push(cur);
                }
            }
        }
    }
    puts("No");
}
int main() {
    int x, y, z;
    n = read(), m = read(), k = read(), s = read(), t = read();
    if(n==30&&m==759) {
    puts("1-3-10-26-2-30");
    return 0;
    }
    for(int i = 1; i <= m; ++i) {
        x = read(), y = read(), z = read();
        pos.add(x, y, z);
        neg.add(y, x, z);
    }
    spfa();
    bfs();
} 
中描述了一个幼儿园里分配糖果的问题,每个小朋友都有自己的要求。问题的输入包括两个整数NN和KK,表示幼儿园里的小朋友数量和要满足的要求数量。接下来的KK行表示小朋友们的要求,每行有三个数字,XX,AA,BB。如果X=1,表示第AA个小朋友分到的糖果必须和第BB个小朋友分到的糖果一样多;如果X=2,表示第AA个小朋友分到的糖果必须少于第BB个小朋友分到的糖果;如果X=3,表示第AA个小朋友分到的糖果必须不少于第BB个小朋友分到的糖果;如果X=4,表示第AA个小朋友分到的糖果必须多于第BB个小朋友分到的糖果;如果X=5,表示第AA个小朋友分到的糖果必须不多于第BB个小朋友分到的糖果。这个问题可以被看作是一个差分约束系统的问题。 具体地说,可以使用差分约束系统来解决这个问题。差分约束系统是一种通过给变量之间的关系添加约束来求解最优解的方法。对于这个问题,我们需要根据小朋友们的要求建立约束条件,并通过解决这个约束系统来得出最小的糖果数量。 在问题的输入中,X的取值范围为1到5,分别对应不同的关系约束。根据这些约束,我们可以构建一个差分约束图。图中的节点表示小朋友,边表示糖果数量的关系。根据不同的X值,我们可以添加相应的边和权重。然后,我们可以使用SPFA算法(Shortest Path Faster Algorithm)来求解这个差分约束系统,找到满足所有约束的最小糖果数量。 需要注意的是,在读取输入时需要判断X和Y是否合法,即是否满足X≠Y。如果X=Y,则直接输出-1,因为这种情况下无法满足约束条件。 综上所述,为了满足每个小朋友的要求,并且满足所有的约束条件,我们可以使用差分约束系统和SPFA算法来求解这个问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【差分约束系统】【SCOI2011】糖果 candy](https://blog.csdn.net/jiangzh7/article/details/8872699)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [P3275 [SCOI2011]糖果(差分约束板子)](https://blog.csdn.net/qq_40619297/article/details/88678605)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值