1. 程式人生 > >P4542 [ZJOI2011]營救皮卡丘

P4542 [ZJOI2011]營救皮卡丘

span return 覆蓋問題 一次 發現 ret pty 最短 最小覆蓋

傳送門

分析一下題目,發現每個點必須至少走過一次,並且對於一個人的路徑,他摧毀的點編號一定是遞增的

並且在摧毀點 $i$ 之前,他不能經過 $i+1$ 到 $n$ 的點,考慮設 $dis[i][j],i<j$ 表示從 $i$ 到 $j$,不經過比 $j$ 大的點的最短路徑

因為最終每個點都會被摧毀,那麽一個人的總路程就是 $dis[0][p_1]\sum_{i=2}^{n}dis[p_{i-1}][p_i]$ ($p_i$ 表示這個人摧毀的第 $i$ 個點),發現這其實就是最小覆蓋問題

所以直接套上去就好了,代碼中把點的編號都 $+1$ 了,註意 $long\ long$

#include<iostream>
#include
<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<0||ch>9) { if(ch==-) f=-1; ch=getchar(); } while(ch>=
0&&ch<=9) { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=1e5+7,M=1e7+7,INF=1e9+7; int fir[N],from[M],to[M],val[M],cst[M],cntt=1; inline void add(int a,int b,int c,int d) { from[++cntt]=fir[a]; fir[a]=cntt; to[cntt]=b; val[cntt]=c; cst[cntt]=d;
from[++cntt]=fir[b]; fir[b]=cntt; to[cntt]=a; val[cntt]=0; cst[cntt]=-d; } int dis[N],mif[N],pre[N],S,T; queue <int> q; bool inq[N]; bool SPFA() { for(int i=S;i<=T;i++) dis[i]=INF; q.push(S); inq[S]=1; dis[S]=0,mif[S]=INF; while(!q.empty()) { int x=q.front(); q.pop(); inq[x]=0; for(int i=fir[x];i;i=from[i]) { int &v=to[i]; if(!val[i]||dis[v]<=dis[x]+cst[i]) continue; dis[v]=dis[x]+cst[i]; pre[v]=i; mif[v]=min(mif[x],val[i]); if(!inq[v]) q.push(v),inq[v]=1; } } return dis[T]<INF; } ll ans; void upd() { for(int now=T,i=pre[T]; now!=S; now=to[i^1],i=pre[now]) val[i]-=mif[T],val[i^1]+=mif[T]; ans+=1ll*mif[T]*dis[T]; } int n,m,K,D[307][307]; int main() { n=read()+1,m=read(),K=read(); S=0,T=(n<<1)+1; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) D[i][j]=INF; D[i][i]=0; } int a,b,c; for(int i=1;i<=m;i++) { a=read()+1,b=read()+1,c=read(); D[a][b]=D[b][a]=min(D[a][b],c); } for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(k<max(i,j)) D[i][j]=min(D[i][j],D[i][k]+D[k][j]); add(S,1,K,0); for(int i=2;i<=n;i++) { if(D[1][i]<INF) add(1,n+i,1,D[1][i]); add(n+i,T,1,0); add(S,i,1,0); for(int j=i+1;j<=n;j++) if(D[i][j]<INF) add(i,n+j,1,D[i][j]); } while(SPFA()) upd(); printf("%lld",ans); return 0; }

P4542 [ZJOI2011]營救皮卡丘