1. 程式人生 > 實用技巧 >2020牛客暑期多校訓練營(第五場)A Portal 題解

2020牛客暑期多校訓練營(第五場)A Portal 題解

題意:

n( n<=300 )個點m條邊( m<=40000 )的帶邊權無向連通圖,要求按順序經過a1 b1 a2 b2 ……ak bk,( k<=300 )你有一個傳送門,可以隨時在腳下放置一個傳送門,兩個傳送門之間可以相互傳送,但場上最多同時存在兩個傳送門,你可以在任意時候關掉任意一個傳送門。問走過這2k個點最短路程是多少。

當時第一反應是設f[x][y][z]為在ak點打算走到bk點,傳送門在y z時的最短路程,但是發現時間複雜度不對。後來想到這張圖可以做最小生成樹簡化成一個樹,這樣路徑就好找多了。然後發現有這麼一個美妙的性質:當場上有兩個傳送門時,當且僅當我們站在一個傳送門所在點時這兩個傳送門對我們都有意義,否則只有一個傳送門對我們有意義。

那麼狀態就可以簡化了,我們設f[x][y]為在ak點,打算向bk點走,有一個傳送門在y點時的最短路程,y=0 時說明場上還沒有傳送門。

接下來,我們列舉是否在ak走向bk的過程中放置傳送門,以及以怎樣的路徑放置。bk到ak+1的過程同理。

  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<queue>
  5 #include<cmath>
  6 #include<cstring>
  7 #include<algorithm>
  8
#define N 305 9 using namespace std; 10 int n,m,zz,a[N],K; 11 struct ro{ 12 int to,next,l; 13 }road[N*N*2]; 14 void build(int x,int y,int z) 15 { 16 zz++; 17 road[zz].to=y; 18 road[zz].next=a[x]; 19 road[zz].l=z; 20 a[x]=zz; 21 } 22 long long dis[N][N]; 23 queue<int
> q1; 24 bool rd[N]; 25 void spfa(int S) 26 { 27 memset(rd,0,sizeof(rd)); 28 rd[S]=1;q1.push(S); 29 dis[S][S]=0; 30 while(!q1.empty()) 31 { 32 int x=q1.front();q1.pop(); 33 rd[x]=0; 34 for(int i=a[x];i;i=road[i].next) 35 { 36 int y=road[i].to; 37 if(dis[S][y]>dis[S][x]+road[i].l) 38 { 39 dis[S][y]=dis[S][x]+road[i].l; 40 if(!rd[y]) 41 { 42 rd[y]=1; 43 q1.push(y); 44 } 45 } 46 } 47 } 48 } 49 int F[N][2]; 50 long long f[2][N]; 51 int main() 52 { 53 memset(dis,0x3f,sizeof(dis)); 54 scanf("%d%d%d",&n,&m,&K); 55 for(int i=1;i<=m;i++) 56 { 57 int x,y,z; 58 scanf("%d%d%d",&x,&y,&z); 59 build(x,y,z); 60 build(y,x,z); 61 } 62 for(int i=1;i<=n;i++) 63 { 64 spfa(i); 65 } 66 for(int i=1;i<=K;i++) 67 { 68 scanf("%d%d",&F[i][0],&F[i][1]); 69 } 70 int nw=1,la=0; 71 long long mx; 72 for(int j=0;j<=n;j++) f[0][j]=f[1][j]=1e15; 73 mx=f[0][0]; 74 f[nw][0]=0; 75 F[0][1]=1; 76 for(int i=1;i<=K;i++) 77 { 78 nw^=1,la^=1; 79 for(int j=0;j<=n;j++) f[nw][j]=1e15; 80 int x=F[i-1][1],y=F[i][0]; 81 for(int j=0;j<=n;j++) 82 { 83 if(!j) 84 { 85 f[nw][0]=min(f[nw][0],f[la][0]+dis[x][y]); 86 } 87 else 88 { 89 f[nw][j]=min(f[nw][j],f[la][j]+dis[x][y]); 90 for(int k=0;k<=n;k++) 91 { 92 f[nw][j]=min(f[nw][j],f[la][k]+dis[x][j]+dis[j][y]); 93 f[nw][j]=min(f[nw][j],f[la][k]+dis[k][j]+dis[j][y]); 94 f[nw][j]=min(f[nw][j],f[la][k]+dis[k][j]+dis[k][y]); 95 f[nw][j]=min(f[nw][j],f[la][k]+dis[x][j]+dis[k][y]); 96 } 97 } 98 } 99 100 nw^=1,la^=1; 101 for(int j=0;j<=n;j++) f[nw][j]=1e15; 102 x=F[i][0],y=F[i][1]; 103 for(int j=0;j<=n;j++) 104 { 105 if(!j) 106 { 107 f[nw][0]=min(f[nw][0],f[la][0]+dis[x][y]); 108 } 109 else 110 { 111 f[nw][j]=min(f[nw][j],f[la][j]+dis[x][y]); 112 for(int k=0;k<=n;k++) 113 { 114 f[nw][j]=min(f[nw][j],f[la][k]+dis[x][j]+dis[j][y]); 115 f[nw][j]=min(f[nw][j],f[la][k]+dis[k][j]+dis[j][y]); 116 f[nw][j]=min(f[nw][j],f[la][k]+dis[k][j]+dis[k][y]); 117 f[nw][j]=min(f[nw][j],f[la][k]+dis[x][j]+dis[k][y]); 118 } 119 } 120 } 121 } 122 long long ans=mx; 123 for(int i=0;i<=n;i++) 124 { 125 ans=min(ans,f[nw][i]); 126 } 127 printf("%lld\n",ans); 128 return 0; 129 }
View Code