タイトル説明
土壌が均等に最近非常によく感じていない吸収、彼は遠い場所で医師が、病気を見に行くことにしました。土壌が均等ルチが吸収され、彼はいじめの学校を見つけたので、私は、取るべき道を知りません。
学びPaが言う:ここでの合計\(N \)町、町間の合計(M \)\双方向の道路は、各道路は3つの属性があります\(u_i \)、\ (V_I \)と\(C_Iは、 \) 。\(u_i \)と\(V_I \)は、それが接続されている町を表し(C_I \)\コストを表します。場合町を通るときに土壌町へと授業料の大きな町の外の道路のコストで(開始および終了を含む)に均等に均一。
均等に吸収された土壌は、医師の診察をするために最もお金を費やすしたいのですが、彼はあなたが賢いを見つけたので、彼は、プログラムされない、私はあなたが彼がこの問題を解決するのに役立つことを願って。
入力形式
最初の入力ラインは2つの正の整数である\(N- \)と\(M \) 、道路、都市図の数。(均等に吸収土壌\(1 \)町番号、疾患\ N(\)一様均一な土壌を確保するため番街は、到達することができるであろう(N \)\町番号)
次\(M \) 3つの正の整数の行\(u_i \)、\ (V_I \)、\ (C_I \) 、面としての意味表題。
出力フォーマット
出力は、唯一の費用にお金の土壌に均一に均一な最小数を表す整数です。
データ範囲
試験時間制限\(5000 \ \ mathrm MS {} \) 、スペースの制約\(256 \ \ mathrmのMIB} {\) 。
- 用(30 \%\)\データ、\(2 \ N-LE \ル10 \)、\ (1 \ルM \ル10 \。) 。
- 用(50 \%\)\データ、\(2 \ N-LE \ル5000 \)、\ (1 \ルM \ 20000ル\。) 。
- 用(100 \%\)\、データ(2 \ N-LE \ル。5 ^ 10 \)\ \、(\ ^ 10 5回\ 1 \ルM \ル2) 。
保证\(1 \とu_i、V_I \ n \)、\ (u_i \ NEQ V_I \)、\ (1 \とC_I \ 10 ^ 6 \) 。
分析
この問題は、癌である......コードは、ああ、数時間をノックしました。
しかし、まだあなたはすべての後、ノックすることを示唆している、良い質問です。
(\ 30 \ \ mathtt {PTS} \)
どのようにどのように暴力へ。
(\ 50 \ \ mathtt {PTS} \)
2つの可能なアプローチがあります:
最初のノードとして扱わそれぞれの右側にあり、そして、対応するエッジ、最大値側の両側に2つのノード間の新たなノードの正しい値に接続されています。
新しいマップのうち、このようなビルドが直接解決するための最短経路を実行することができます。
空間はに貼り付けてもよい\(\ mathcal {O}(M ^ 2)\) 。
最短ラン、ノードの現在の状態についてのレコードがそこから来るときに、第2です。
リラックスしたときにこのように、あなたは現在のエッジの重みを計算することができます。
時間の複雑さは、やはり気になります。
\(100 \ \ mathtt {PTS} \)
悪い習慣を考えるのは本当に難しいです。
次に、私はあなたが方法、原因やアイデアの実践を整理与えます。
まず第一に、我々は最初のアプローチは、再構築のアプローチにその数字であることがわかります。
このアプローチは、建物側のボトルネック、エッジレベルである場合\(\ mathcal {O}( M ^ 2)\) 。
だから、どのように我々は落ちるエッジの数の順に、サイドを構築するのですか?
次の図は、:(注:プレゼンテーションを容易にするため、標準的なデフォルトのエッジの重みはありません重量である\(0 \) )。
まず、最大のもの右側縁として、すべてのパスを、このエッジの右側に、この側から引き出されているが計算されます。
さて、私たちは、建設側を考慮することはできません。
ですから違いは何\(Q \オメガQ \)
次に、二番目に大きいエッジを考えます。Taの側は、すべての側面にTaよりもさらに小さくする必要があります。
しかし、小さな側にもエッジの側の上にすべての第二位と第二位などの側に私たちの最大の側面。さて、私たちはそう動作することはできません。
- 最大のポイントのために、あなたが通過することができ
?
て、ノード、および!
他のノードに到達するためにノード。 - 二番目に大きいノードに対して、それが指示することができ
!
、ノードは、Taノードより小さい到達します。
このように、我々はエッジを大幅に節約することができそうではありませんか?
このようなと、そのようなので、私たちはマップを構築することができます。
複雑?
ラウンド正しく適切に各エッジ、ループ、\(\シータ(M)\) 。
???など、タイトルはこのああがどのように、それは双方向の側であることを意味するものではありませんか?それは一方通行ではないでしょうか?
門司、我々最初の逆マップが構築されました。
加重後のリバース位置に注意してください。それ以外の場合は、間違っているだろう。
???オリジナルのエッジがアップターンにあなたはそこだろうか?私に嘘をつきません!
確かにちょうど上げるが、絵は、ああそうです。あなたがしようとは思わない(Q \オメガQ \)\。
わかりましたので、2枚の写真は、どのようにそれを行うには?ないことの良いAの画像その?
非常に単純な限り、図中の同一部分内の2つのノードを組み合わせて、それが可能です。
しかし、マージすることができない、いくつかの中間ノード。これらのノードは、関係の異なる方向及び大きさを表すため。
その後の最短部分の喜び、Sahua ~~✿✿ヽ(゜▽゜)テクノ✿があります。
エヘン、私たちは広がりを過ごすために何を、ルの複雑さを数えていません。
グラフのエッジの新しい数がよりオリジナルよりもないが複雑で、主に最短である時間(\ 12 \)倍(\ \シータ(m)は)\、それが最終的に複雑である(\シータ(M \ \ログM)\) (定数は、それがダイクストラフィボナッチヒープを最適化するために使用される場合、それは小さくすることができ、実装最終コードに依存するが、スタックはダイクストラを最適化することである場合、)上で実行することが容易です。
コード
これは、コードサイズです\(200 \)ライン+タイトルああ......
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
#define FRONT_SMALLER 0
#define FRONT_BIGGER 1
#define BACK_SMALLER 2
#define BACK_BIGGER 3
#define CENTER 4
typedef long long ll;
const int max_n = 100000, max_m = 200000;
struct st_t
{
int val, id;
bool operator<(const st_t& a) const { return val < a.val; }
};
struct hp_elem
{
int id;
ll val;
hp_elem(int _i = 0, ll _v = 0) : id(_i), val(_v) { }
bool operator<(const hp_elem& k) { return val < k.val; }
};
class heap
{
private:
hp_elem s[max_m*5+1];
int len;
inline int lson(int id) { return id << 1; }
inline int rson(int id) { return (id << 1) | 1; }
inline int par(int id) { return id >> 1; }
inline void swap(int id) { hp_elem tmp = s[id]; s[id] = s[par(id)], s[par(id)] = tmp; }
public:
heap() : len(0) { }
void insert(hp_elem n)
{
s[++len] = n;
int p = len;
while (p != 1 && s[p] < s[par(p)])
{
swap(p);
p = par(p);
}
}
hp_elem query() const { return s[1]; }
bool is_empty() const { return !len; }
void remove()
{
s[1] = s[len--];
int p = 1, t;
while (rson(p) <= len)
{
if (s[lson(p)] < s[rson(p)])
t = lson(p);
else
t = rson(p);
if (s[t] < s[p])
{
swap(t);
p = t;
}
else
return;
}
if (lson(p) <= len && s[lson(p)] < s[p])
swap(lson(p));
}
};
namespace ZBSAKIOI
{
int hd[max_n+2], des[(max_m+2)<<1], val[(max_m+2)<<1], nxt[(max_m+2)<<1], edge_cnt = 0;
void add_edge(int s, int t, int v)
{
des[edge_cnt] = t, val[edge_cnt] = v;
nxt[edge_cnt] = hd[s], hd[s] = edge_cnt++;
}
}
st_t tmp[max_m];
heap hp;
int hd[max_m*5+10], des[max_m*12+24], val[max_m*12+24], nxt[max_m*12+24], edge_cnt = 0;
ll dis[max_m*5+10];
bool vis[max_m*5+10] = {};
inline int read()
{
int ch = getchar(), n = 0, t = 1;
while (isspace(ch)) { ch = getchar(); }
if (ch == '-') { t = -1, ch = getchar(); }
while (isdigit(ch)) { n = n * 10 + ch - '0', ch = getchar(); }
return n * t;
}
inline int get_id(int p_id, int n_id) { return p_id * 5 + n_id; }
void add_edge(int s, int t, int v)
{
des[edge_cnt] = t, val[edge_cnt] = v;
nxt[edge_cnt] = hd[s], hd[s] = edge_cnt++;
}
int main()
{
memset(ZBSAKIOI::hd, -1, sizeof(ZBSAKIOI::hd));
memset(hd, -1, sizeof(hd));
memset(dis, 0x3f, sizeof(dis));
int n = read(), m = read(), ta, tb, tc, st, ed;
hp_elem cur;
for (int i = 0; i < m + 2; i++)
{
if (i < m)
ta = read() - 1, tb = read() - 1, tc = read();
else if (i == m)
ta = n, tb = 0, tc = 0;
else
ta = n - 1, tb = n + 1, tc = 0;
ZBSAKIOI::add_edge(ta, tb, tc);
ZBSAKIOI::add_edge(tb, ta, tc);
add_edge(get_id((ZBSAKIOI::edge_cnt - 1) >> 1, CENTER), get_id((ZBSAKIOI::edge_cnt - 1) >> 1, BACK_BIGGER), tc);
add_edge(get_id((ZBSAKIOI::edge_cnt - 1) >> 1, CENTER), get_id((ZBSAKIOI::edge_cnt - 1) >> 1, BACK_SMALLER), 0);
add_edge(get_id((ZBSAKIOI::edge_cnt - 1) >> 1, BACK_BIGGER), get_id((ZBSAKIOI::edge_cnt - 1) >> 1, CENTER), 0);
add_edge(get_id((ZBSAKIOI::edge_cnt - 1) >> 1, BACK_SMALLER), get_id((ZBSAKIOI::edge_cnt - 1) >> 1, CENTER), tc);
add_edge(get_id((ZBSAKIOI::edge_cnt - 2) >> 1, CENTER), get_id((ZBSAKIOI::edge_cnt - 2) >> 1, FRONT_BIGGER), tc);
add_edge(get_id((ZBSAKIOI::edge_cnt - 2) >> 1, CENTER), get_id((ZBSAKIOI::edge_cnt - 2) >> 1, FRONT_SMALLER), 0);
add_edge(get_id((ZBSAKIOI::edge_cnt - 2) >> 1, FRONT_BIGGER), get_id((ZBSAKIOI::edge_cnt - 2) >> 1, CENTER), 0);
add_edge(get_id((ZBSAKIOI::edge_cnt - 2) >> 1, FRONT_SMALLER), get_id((ZBSAKIOI::edge_cnt - 2) >> 1, CENTER), tc);
}
for (int i = 0; i < n + 2; i++)
{
tc = 0;
for (int p = ZBSAKIOI::hd[i]; p != -1; p = ZBSAKIOI::nxt[p], tc++)
tmp[tc].val = ZBSAKIOI::val[p], tmp[tc].id = p;
sort(tmp, tmp + tc);
if (i == n)
st = get_id(tmp[tc-1].id >> 1, ((tmp[tc-1].id - (tmp[tc-1].id >> 1 << 1)) << 1) + 1);
else if (i == n + 1)
ed = get_id(tmp[0].id >> 1, ((tmp[0].id - (tmp[0].id >> 1 << 1)) << 1) + 1);
for (int i = 1; i < tc; i++)
{
ta = tmp[i-1].id, tb = tmp[i].id;
add_edge(get_id(ta >> 1, (ta - (ta >> 1 << 1)) << 1), get_id(tb >> 1, (tb - (tb >> 1 << 1)) << 1), 0);
add_edge(get_id(tb >> 1, ((tb - (tb >> 1 << 1)) << 1) + 1), get_id(ta >> 1, ((ta - (ta >> 1 << 1)) << 1) + 1), 0);
}
}
dis[st] = 0;
hp.insert(hp_elem(st, 0));
while (!hp.is_empty())
{
cur = hp.query();
hp.remove();
if (!vis[cur.id])
{
vis[cur.id] = true;
for (int p = hd[cur.id]; p != -1; p = nxt[p])
if (dis[des[p]] > dis[cur.id] + val[p])
{
dis[des[p]] = dis[cur.id] + val[p];
if (!vis[des[p]])
hp.insert(hp_elem(des[p], dis[des[p]]));
}
}
}
printf("%lld\n", dis[ed]);
return 0;
}
追伸
これは、頭の後ろを記入5ABレポートを読んで問題の解決策の主な内容ですが、私はあなたが理解し、気持ちをリフレッシュすることができます願っています。
5ABは、その説明は、より自然なことができ、それはのような奇妙なアイデアを持っていませんします。この問題の解決策は、書き込みにこの概念に付着しています。
あなたがあなた自身の意見を持っている場合、Huanyinはあなたのコメントを残します。