POJ - 1860: 通貨交換と最短パスの変形 - 最小最大値

タイトル説明:

N 個のポイント、M 個のエッジ、各エッジには値があります。ポイント 1 からポイント N までのパスを見つけるには、パス内の最小エッジ重みを最大化する必要があります。                           

入力:

複数の入力セットの場合、最初の行にはTが表示されます。
各グループの最初の行には、2 つの数値 n と m が示されています。(1 <= n <= 1000)
次の m 行。各行には、パスの 2 つの端点とエッジの重みを表す 3 つの数値 u、v、w が含まれます。 

(1 <= u、v <= n、0< w <= 1e6)
2 点間にエッジは 1 つだけあり、グラフは無向です。出力:

i 番目のデータグループは、最初に「Scenario #i:」を出力し
、次にパス上の最小エッジ重みを出力し、最後に空行を出力します。
保証されたソリューション

例:

サンプル入力: サンプル出力
シナリオ #1:
3 3 1
1 2 3
1 3 4
2 3 5

アイデア: 

この問題は一見すると最短経路を見つけてダイクストラで解くという非常に単純な問題なのですが、よくよく考えてみると「最小値が最大」というところが混乱してしまいます。は「数学的数値問題」ですが、授業を受けてみるとそうではないと感じました。この問題の最小値と最大値はダイクストラに関連しており、非常に似ているとも言えますが、原理は難しいです。わかりました。よく勉強しましょう。

通常のディクストラと最小最大値

通常のダイクストラでは、最適化を行わず緩和演算のみを使用するコードであっても、最適化のために優先キューを使用するコードであっても、その最も重要な演算は、問題がどのように解決されるか、他のアルゴリズムとどのようにネストされるかは関係ありません。 if(dis[v ]>dis[u]+w) dis[v]=dis[u]+w;」は常に同じです。

最小値と最大値については原理がわかりにくいですが、ダイクストラのコアコードのごく一部を変更するだけです。上記のコードを「if(dis[v]>max(dis[u],w) dis[v]=dis[u]+w;」に変更します。わかりにくい人は暗記してください。                                                                                                                                           

最小値最大値の原則:
"
重み付き有向グラフで単一ソースの最短経路問題を解く場合、開始点 s から他のすべてのノードまでの最短経路を見つける必要があります。この問題では、経路の長さはすべてのノードの重みを指します。そして、「パス内のエッジ重みの最小値が最大である」とは、始点 s から他のノードまでのすべてのパスについて、エッジ重みの最小値が最も大きいパスを次のように選択することを意味します。最短パス。つまり、最短パスの長さは、すべてのパスの中で最大の最小エッジ重みを持つパスの最小エッジ重みです。たとえば、開始点が s である重み付き有向グラフがあるとします 
。グラフには 3 つのパス s->t があります。エッジの重みはそれぞれ 2、3、4 です。定義によれば、「パス内のエッジの重みの最小値が最大です」 「エッジの重みの最小値が最大のパスを最短パスとして選択する必要があります。この例では、エッジの重みの最小値が最大のパスが 3 番目のパスです。最小エッジの重みが 4 であるため、このパスは 3 番目のパスになります。一方、他の 2 つのパスの最小エッジ重みは 2 と 3 です。したがって、最短パスの長さは 4 です。2 つのパスの最小エッジ重みが同じである場合、多くのパスがあることに注意してください。そのうちの 1 つを最短経路として選択します。同時に、始点 s から終点 t までの経路が存在しない場合、最短経路の長さは無限になります。

この部分では、ダイクストラとその変形の最も基本的な違いについて詳しく説明しています。「最小値が最大である」とは、1 つの点から出る複数の経路を指します。私が行く各点の重みが同じくらい高いことを確認したいのです。できるだけ小さい(少なくとも現在のパスでは2番目のパスの重みの合計がそれより小さいことが分かりません)、歩いた複数のパスのうち、最も重みが大きいパスを選択して出力します、 " if(dis[v]>max(dis[u],w) dis[v]=dis[u]+w;" この文により、キューから取り出した各ポイントの重みが確実にcurrent メソッドでは、各パスが「最小値」機能に到達できるように最小のものです。キューを終了した後、main 関数で min を使用して各「最小値」パスを選別します。唯一のパスをフィルターで除外します。条件を満たすものです。


この質問に対するアイデア: 

タイトルに一意の解を持たせると書いてあるので、この問題は特殊判定の難易度を簡略化できるので、ディクストラを上で紹介した「最小値と最大値」の特徴に合わせて細部にまで気を配って変形させました。注意深く慎重に」 コードを完成させるだけです。

コードを添付します:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <queue>
#include <map>
#include <vector>

const int N = 1005;

struct EDGE {
    int v, w, next;
} e[N * N * 2];

int head[N], tot = 1;
int father[N];

void add(int u, int v, int w) {//普通dijkstra建边无需多说
    e[tot].v = v;
    e[tot].w = w;
    e[tot].next = head[u];
    head[u] = tot ++;
}

void init(int n) {//对father数组进行初始化,一开始都没有父节点,将其值赋为-1
    tot = 1;
    for (int i = 0; i <= n; i++) {
        head[i] = 0;//初始化
        father[i] = -1;
    }
}

struct Node {
    int pos, dis;

    Node() {};

    Node(int pos, int dis): pos(pos), dis(dis) {};

    bool operator < (const Node &r) const {
        return dis > r.dis;
    }
};

int dis[N], vis[N];

void dijkstra(int s) {
    std::priority_queue<Node> q;
    memset(dis, 0x3f, sizeof dis);
    memset(vis, 0, sizeof vis);
    dis[s] = 0;
    q.push(Node(s, 0));
    while (!q.empty()) {
        Node f = q.top();
        q.pop();
        int u = f.pos;
        if (vis[u]) continue;
        vis[u] = 1;
        for (int i = head[u]; i; i = e[i].next) {
            int v = e[i].v;
            int w = e[i].w;
            if (!vis[v] && dis[v] > std::max(dis[u], w)) {
                dis[v] = std::max(dis[u], w);
                q.push(Node(v, dis[v]));
                father[v] = u;
            }
        }
    }
}

void solve() {
    int n, m;
    std::cin >> n >> m;
    init(n);//进行初始化
    for (int i = 0; i < m; i++) {
        int u, v, w;
        std::cin >> u >> v >> w;
        add(u, v, w);
    }
    dijkstra(1);
    int p = n;
    int ans = 0x3f3f3f3f;
    while (p != 1) {//对应init函数father数组赋-1的行为,说明p=-1到了终点需退出
        ans = std::min(ans, dis[p]);
        p = father[p];
    }
    std::cout << ans << '\n';
}

int main() {
    // freopen("/Users/chant/in.txt", "r", stdin);
    int T;
    std::cin >> T;
    for (int i = 1; i <= T; i++) {
        printf("Scenario #%d:\n", i);
        solve();
    }
    return 0;
}

 概要: この問題は最小値最大値とダイクストラの変形に関するテンプレート問題であり、最小値最大値の意味を理解することが重要で、残りは非常に簡単です。

作成は簡単ではありません。売春行為はしないでください。スリーリンク+注目をお願いします!ありがとう! 

おすすめ

転載: blog.csdn.net/2301_76331300/article/details/131652062