給定一張 \(n\) 個點 \(m\) 條邊的連通圖,圖中每條邊都有乙個非負邊權,點的編號從 1 開始. 現在你有 \(k\) 個任務,第 \(i\) 個任務需要你先到達點 \(a_i\), 然後到達點 \(b_i\). 你需要依次完成這 \(k\) 個任務. 初始時你在 1 號點.
現在你手裡有一把槍,當你在 \(u\) 號點朝地上開槍時,\(u\) 上就會建立乙個傳送門. 開槍消耗的時間可以忽略不計. 如果你在 \(u\), \(v\) 兩點都建立了傳送門,那麼你就可以在這兩點間不計消耗地任意傳送(你可以將其視作圖中加入了一條連線 \(u, v\) 且邊權為 0 的邊).
遺憾的是,這張圖中同時只能存在 2 個傳送門. 因此當圖中存在了 2 個傳送門,且你需要再建立乙個傳送門時,你必須先選擇乙個已經建立的傳送門並關閉它. 關閉傳送門的消耗同樣是忽略不計的,並且你可以關閉處在任
意位置的傳送門,與你當前所在的位置無關.
請求出完成這 \(k\) 個任務最少需要走過的距離.
第一行三個整數 \(n, m, k\) ,分別代表圖中點的個數、邊的條數、任務的個數.
接下來 \(m\) 行,每行三個整數 \(u, v, w\) ,表示圖中有一條連線 \(u, v\) ,且邊權為 \(w\) 的邊.
接下來 \(k\) 行,每行兩個整數 \(a_i\), \(b_i\) ,表示第 \(i\) 個任務需要到達的兩個點.
輸出一行乙個整數表示答案.
5 4 2
1 2 1
2 3 1
3 4 1
4 5 1
1 52 4
5
6 10 3
1 1 3
3 1 1
6 2 3
1 6 10
4 1 1
3 1 2
5 6 9
5 4 10
6 3 4
3 4 4
3 53 6
6 5
16
對於\(30\%\)的資料,\(1 \leq n,k \leq 50\)
另有\(30\%\)的資料,\(m=n-1\)
對於\(100\%\)的資料,\(1 \leq n, k\leq 300,1 \leq m \leq 40000,0 \leq w \leq 10^9\)
時間限制: \(1s\)
空間限制: \(512m\)
經過觀察我們發現n很小,因此先跑一遍floyd預處理出兩兩之間的最短路。
然後我們再觀察傳送門的性質,可以發現,雖說有兩個傳送門,但實際上可以看作是乙個傳送門,然後你從任意乙個點都能到達傳送門所在的那個點(只需把另乙個傳送門放到你所在的點即可)。
其次,所謂的\(k\)個任務是假的,其實就是\(k\times2\)個任務,每次從上乙個點到達這乙個點。
於是我們考慮設\(f[i][j]\)表示完成前\(i\)個任務,當前有乙個傳送門在\(j\)的最優方案路徑長。(\(1\leq i \leq k \times 2,1 \leq j \leq n\))
考慮轉移(x表示當前任務要到達的點,now表示上乙個任務要到達的點(now初始化為1)):
1.\(f[i][j]=f[i-1][j]+min(dis[j][x],dis[now][x]);\)
若把傳送門設在\(j\)這個位置,可以是之前傳送門就在\(j\),於是我們可以傳送到\(j\)然後走到\(x\),或者直接從上一次到達的點走到\(x\).
2.\(f[i][j]=f[i-1][k]+min(dis[j][k],dis[now][k])+min(dis[k][x],dis[j][x])\);
不難理解,若之前傳送門在\(k\),那麼我們為了把傳送門設在\(j\)位置,可以先由\(now\)或\(k\)位置走到\(j\),設下傳送門,然後從\(j\)或\(k\)位置走到\(x\).
最後輸出\(f[k][now]\)即可.
ps:我用的dp用了滾存優化空間( 實際沒必要 ),
**如下(馬蜂很醜,不喜勿噴)——
#include#define tp template#define ts template#define reg register
#define ri reg int
#define con const
#define ci con int&
#define i inline
#define w while
#define maxn 305
#define maxm 80005
#define inf 214748364998244353
#define ll long long
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,m,k,tot,fir[maxn],nxt[maxm],son[maxm],w[maxm];ll ans=inf,f[2][maxn],dis[maxn][maxn];
inline void add(int x,int y,int z)
class fileinputoutput
tp inline void read(t& x)
tp inline void write(t x,const char& ch)
inline void flush(void)
#undef tc
#undef pc
}f;int main()
k<<=1;int now=1;memset(f,63,sizeof(f));
f[0][1]=0;for(register int k=1,x,op=(k&1);k<=k;now=x,op^=1,k++)
} f.write(f[k&1][now],'\n');return f.flush(),0;
}
GJGHFD的排列 題解 DP
給定乙個長度為 n 的排列 p 1 p 2 p n 你可以做以下兩個操作之一 1.將 p 移到 p 1 之前,即 p 1 p 2 p n rightarrow p p 1 p 2 p p n 2.將 p 移到 p n 之後,即 p 1 p 2 p n rightarrow p 2 p 3 p p n...
解鎖 傳送門
linenoise c命令列處理工具 catch2 c 測試框架 quick start linenoise ng linenoise next generation c 命令列處理工具 yarn 快速 可靠 安全的node包依賴管理工具 pandoc pandoc安裝 使用 快速上手 autope...
JZOJ A組 傳送門
8102年,normalgod在glados的幫助下,研製出了傳送槍。但glados想把傳送槍據為己有,於是把normalgod扔進了一間實驗室。這間實驗室是一棵有n個節點的樹。現在normalgod在一號節點,出口也在一號節點,但為了開啟它,必須經過每乙個節點按下每個節點的開關,出口才能開啟。gl...