興味深い話題が、良いコードを望んでも、本当に、それは州のトピックで清流のように記述することができます
我々は出発点としての点の列挙を考慮して、他のポイントへの暴力の最短経路を見つけた場合、あなたは暴力の問題を解決することができます
一方、しかし、我々は、変換について少し問題を抱えている収集ポイントの数の推測の数に相当をしながら出発点としては、最低限このうち、残りのすべてのポイントの他最短に走っ
具体的な実装では、スーパー起点構築するために非常にシンプルで簡単です\(ST \)と終了\(タールを\)このキーの場合は、\(X \)は、コレクションの出発点でそうでもあり、xに\(ST \ヴァル = 0 \ )エッジ、さらにセットの終わりに\(X \タール、ヴァル = 0 \) エッジ
最後に\(タールST \は\)最短経路で答えが、それは非常に単純なようです
しかし、我々は最終的な答えがされている場合、薄い、この方法は、非常に良いようだ探していました(y軸の\にX- \)を\場合は、\(のx \)を収集しての出発点に割り当てられている\(のy \)セットの最後に割り当てられていますレーンは、このアルゴリズムは、直接答えを走りました!
我々は簡単に得ることができる上記の分析によれば、ランダム化、全ての側に我々のキー毎にアプローチして、正しい速度となるようにランダムに、最短ランに割り当てられた(\ \ FRAC {1} { 4} \)
期限を実行しているの複雑さにある\(N-ログ\ O(N-)\)(DJ付き)、したがって、私たちの安全な5Sの実行を制限\(20 \)かそこら回なので、エラーの確率は次のとおりです。
\ [(\ FRAC {1} {4})^ {20} \約0.0031712 \約FRAC \ {1}、{315} \]
大きい実行ので、この質問、およびちょうど2100 + MSでLuogu上の最大点を通過するのに十分\(30、40 \)安全なそれを再生するには、メインゲームは、それが全体Tの後ろにある場合(時間がないという問題を恥ずかしいです)
ランダム化CODE
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<queue>
#define RI register int
#define CI const int&
#define Tp template <typename T>
using namespace std;
const int N=1e5+5,M=5e6+5;
const long long INF=1e18;
struct edge
{
int to,nxt,v;
}e[N+M]; int n,t,thead[N],head[N],a[N],cnt,tcnt,m,k,x,y,z,st,tar; long long dis[N];
class FileInputOutput
{
private:
static const int S=1<<21;
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
char Fin[S],*A,*B;
public:
Tp inline void read(T& x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
#undef tc
}F;
class SSSP
{
private:
struct data
{
int id; long long val;
friend inline bool operator < (const data& A,const data& B)
{
return A.val>B.val;
}
}; priority_queue <data> hp; bool vis[N];
public:
#define to e[i].to
inline void Dijkstra(void)
{
RI i; for (i=st;i<=tar;++i) dis[i]=INF,vis[i]=0; dis[st]=0;
hp.push((data){st,0}); while (!hp.empty())
{
int now=hp.top().id; hp.pop(); if (vis[now]) continue;
vis[now]=1; for (i=head[now];i;i=e[i].nxt)
if (dis[to]>dis[now]+e[i].v) hp.push((data){to,dis[to]=dis[now]+e[i].v});
}
}
#undef to
}G;
inline void taddedge(CI x,CI y,CI z)
{
e[++tcnt]=(edge){y,thead[x],z}; thead[x]=tcnt;
}
inline void addedge(CI x,CI y,CI z)
{
e[++cnt]=(edge){y,head[x],z}; head[x]=cnt;
}
inline long long solve(long long ret=INF)
{
RI i,j; for (F.read(n),F.read(m),F.read(k),i=1;i<=m;++i)
F.read(x),F.read(y),F.read(z),taddedge(x,y,z);
for (tar=n+1,i=1;i<=k;++i) F.read(a[i]);
for (i=1;i<=20;++i)
{
for (cnt=tcnt,j=st;j<=tar;++j) head[j]=thead[j];
for (j=1;j<=k;++j) if (rand()&1) addedge(st,a[j],0);
else addedge(a[j],tar,0); if (G.Dijkstra(),dis[tar]<ret) ret=dis[tar];
}
return ret;
}
inline void clear(void)
{
for (RI i=st;i<=tar;++i) thead[i]=0; tcnt=0;
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (srand(20030909),F.read(t);t;--t) printf("%lld\n",solve()),clear(); return 0;
}
それではそれはわずかに設定変更時刻配布ポイント、列挙され、正しいアプローチ、モデリング及び上記とほぼ同様の話\(N \)ビット毎に、ポイント数はこれの範囲内にある場合\(1 \)片側の出発点に、またはその逆
正しさの証拠もまた答えであると仮定して、理解されている(Y軸の\にX- \)を\ので、\(X- \ Y-NEの\) 、したがって\(xは、Y \)はバイナリの異なる少なくとも一つを有していなければならない、少なくともので一度脇にあった、結論を設定しました
これは、することができ(O(N ^ 2ログ\ n)を\)\ 複雑この問題を通じて、ポイントへの答えは、そう列挙するための2つの側面を持っていることに注意してください
バイナリグループのCODE
#include<cstdio>
#include<cctype>
#include<queue>
#define RI register int
#define CI const int&
#define Tp template <typename T>
using namespace std;
const int N=1e5+5,M=5e6+5;
const long long INF=1e18;
struct edge
{
int to,nxt,v;
}e[N+M]; int n,t,thead[N],head[N],a[N],cnt,tcnt,m,k,x,y,z,st,tar; long long dis[N];
class FileInputOutput
{
private:
static const int S=1<<21;
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
char Fin[S],*A,*B;
public:
Tp inline void read(T& x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
#undef tc
}F;
class SSSP
{
private:
struct data
{
int id; long long val;
friend inline bool operator < (const data& A,const data& B)
{
return A.val>B.val;
}
}; priority_queue <data> hp; bool vis[N];
public:
#define to e[i].to
inline void Dijkstra(void)
{
RI i; for (i=st;i<=tar;++i) dis[i]=INF,vis[i]=0; dis[st]=0;
hp.push((data){st,0}); while (!hp.empty())
{
int now=hp.top().id; hp.pop(); if (vis[now]) continue;
vis[now]=1; for (i=head[now];i;i=e[i].nxt)
if (dis[to]>dis[now]+e[i].v) hp.push((data){to,dis[to]=dis[now]+e[i].v});
}
}
#undef to
}G;
inline void taddedge(CI x,CI y,CI z)
{
e[++tcnt]=(edge){y,thead[x],z}; thead[x]=tcnt;
}
inline void addedge(CI x,CI y,CI z)
{
e[++cnt]=(edge){y,head[x],z}; head[x]=cnt;
}
inline long long solve(long long ret=INF)
{
RI i,j; for (F.read(n),F.read(m),F.read(k),i=1;i<=m;++i)
F.read(x),F.read(y),F.read(z),taddedge(x,y,z);
for (tar=n+1,i=1;i<=k;++i) F.read(a[i]);
for (i=1;i<=(n<<1);i<<=1)
{
for (cnt=tcnt,j=st;j<=tar;++j) head[j]=thead[j];
for (j=1;j<=k;++j) if (a[j]&i) addedge(st,a[j],0);
else addedge(a[j],tar,0); if (G.Dijkstra(),dis[tar]<ret) ret=dis[tar];
}
for (i=1;i<=(n<<1);i<<=1)
{
for (cnt=tcnt,j=st;j<=tar;++j) head[j]=thead[j];
for (j=1;j<=k;++j) if (a[j]&i) addedge(a[j],tar,0);
else addedge(st,a[j],0); if (G.Dijkstra(),dis[tar]<ret) ret=dis[tar];
}
return ret;
}
inline void clear(void)
{
for (RI i=st;i<=tar;++i) thead[i]=0; tcnt=0;
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
for (F.read(t);t;--t) printf("%lld\n",solve()),clear(); return 0;
}