ZJOI2011 營救皮卡丘

2022-05-23 21:54:11 字數 1831 閱讀 5372

題面

神仙題。

做最小路徑覆蓋。

有乙個很像的地方,就是最小路徑覆蓋必須覆蓋到每個點,這道題也一樣。

這道題有4個和最小路徑覆蓋不一樣的地方

可以重複訪問(這個可以用$floyed$傳遞閉包解決)

每條路徑必須從原點出發

每個點必須被「到達」(並不能乙個節點成乙個路徑)

假設已經訪問了$1..x$,那麼至少有乙個人,它的訪問序列中第乙個比$x$大的元素為$x+1$

我們從第四點突破,假設已經訪問了$1..x$,那麼至少有乙個人$p_i$,它的訪問序列中第乙個比$x$大的元素為$x+1$,我們稱$p_i$擊破了$x+1$。

顯然,對於乙個合法的路徑覆蓋,乙個人的擊破序列是遞增的,且擊破序列中,每個點出現且僅出現一次。

那我們就直接對擊破序列做最小路徑覆蓋,$dis[i][j]$表示上乙個擊破的是$i$,這次要來擊破$j$了$(i但是這樣還不照,因為對於每個人,我們都需要支付它從$0$到第乙個擊破的點的費用,二分圖上,我們建$k$個新的$0$點,連得邊和老$0$點一樣的。在網路流中,就直接給$0$點流$k$即可。

這樣還是有問題,首先不能保證恰好是$k$條,其次不能保證$k$條都是每條對應乙個起點。

也很簡單。

$k$條都是每條對應乙個起點,因為起點之間沒有連邊,所以不可能有兩個起點在一起的。

總共$n+k$個點,只有最大流是$n$,則恰好就是$k$條,由霍爾定理,$y$部上面的$n$個點肯定飽和,下面$k$個點肯定匹配不到,所以最大流是$n$。

**

#include#include

#include

#include

#include

#include

#include

#include

#define n 500

#define s 0

#define t (2*n+3)

#define ll long long

#define ri register int

#define inf 1000000007

using

namespace

std;

intn,m,k;

intdis[n][n];

struct

graph

bool

spfa()

}vis[x]=0

; }

return dis[t]}

int dfs(int x,int

lim)

}return

sum;

} ll zkw()

return

ret;

}} g;

intmain()

for (ri kk=0;kk<=n;kk++)

for (ri i=0;i<=n;i++)

for (ri j=0;j<=n;j++)

if (kk<=i || kk<=j) dis[i][j]=min(dis[i][j],dis[i][kk]+dis[kk][j]);

for (ri i=1;i<=n+1;i++)

for (ri j=i+1;j<=n+1;j++) if (i!=j) g.add_edge(i,n+1+j,1,dis[i-1][j-1

]); g.add_edge(s,

1,k,0

);

for (ri i=2;i<=n+1;i++) g.add_edge(s,i,1,0

);

for (ri i=n+2;i<=2*(n+1);i++) g.add_edge(i,t,1,0

); cout

}

ZJOI2011 營救皮卡丘

似乎這玩意兒叫做 k 路徑覆蓋問題 可以發現 k 個人每個人走過的點集不相交 就是有 n 個點 m 條邊的圖,邊有邊權,從 0 出發,中途如果經過點 u 那麼之前必須經過點 u 1 可以從點 s 出發最多 k 次,問走到 n 的最小花費 那麼題目就轉化成了用不超過 k 條不相交的鏈覆蓋整張圖的最小代...

ZJOI2011 營救皮卡丘

題目 題目鏈結 思路首先,看資料範圍比較小,想到網路流。對於最短路的那部分,在走到 j 的時候,不能經過 j 的點,所以在 floyd 的時候我們加一層限制 k j 處理出最短路。然後考慮網路流建邊。會發現有這麼幾個限制 從小的點走向大的點 每個點都必須走到 不得超過 k 條路徑 因為每一條路徑一定...

2324 ZJOI2011 營救皮卡丘

題目鏈結 題目大意 n 1個城市 0到n 初始時k個人都在0城市。城市之間有距離。要求 1 遍歷完n個城市 有乙個人遍歷了某個城市就算這個城市被遍歷了 2 遍歷i城市前必須遍歷完前i 1個城 市,並且在遍歷前i 1個城市時不能經過大於等於i的城市。在滿足 1 2 的前提下使得k個人走的總距離最小 題...