题解 P4610 【[COCI2011-2012#7] KAMPANJA】

· · 题解

Solution:

  本题最短路+dp。

  我们先用floyd预处理出w[i][j],表示i\rightarrow j经过的最少点数(除了i点)。

  由于要求1\rightarrow 2\rightarrow 1经过的最少点数,而模型是个有向图,考虑dp,定义状态f[i][j]表示1\rightarrow i\rightarrow j\rightarrow 1经过的最少点数,初始化f[1][1]=1,状态转移方程:f[x][y]=min(f[x][y],f[a][b]+w[b][x]+w[x][y]+w[y][a]-1)(注意-1是因为a被多算了1次),直接dp显然是有后效性的,注意到每次由小的点对更新状态肯定最优,于是状态转移时套用堆优化dijkstra,用全局最小值f[a][b]去更新状态就好了。

  转移时还需注意不能用点对f[a][b]更新自己(当a==b时直接RE)。

  最坏时间复杂度O(n^3\log n)

### 代码: ```cpp /*Code by 520 -- 9.4*/ #include<bits/stdc++.h> #include<ext/pb_ds/assoc_container.hpp> #include<ext/pb_ds/priority_queue.hpp> #define il inline #define ll long long #define RE register #define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++) #define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--) using namespace std; using namespace __gnu_pbds; const int N=205,inf=233333333; int n,m,w[N][N],dis[N][N]; struct node{ int u,v,d; bool operator<(const node &a)const{ if(d==a.d&&u==a.u)return v>a.v; if(d==a.d)return u>a.u; return d>a.d; } }; typedef __gnu_pbds::priority_queue<node,less<node>,pairing_heap_tag> heap; heap q; heap::point_iterator id[N][N]; int main(){ scanf("%d%d",&n,&m); For(i,1,n) For(j,1,n) w[i][j]=i==j?0:inf,dis[i][j]=inf; int u,v; while(m--) scanf("%d%d",&u,&v),w[u][v]=1; For(k,1,n) For(i,1,n) For(j,1,n) w[i][j]=min(w[i][j],w[i][k]+w[k][j]); dis[1][1]=1,id[1][1]=q.push(node{1,1,dis[1][1]}); while(1){ node x=q.top(); int a=x.u,b=x.v;q.pop(); if(a==2&&b==2)break; For(c,1,n) For(d,1,n) { if(a==c&&b==d)continue; if(dis[a][b]+w[b][c]+w[c][d]+w[d][a]-1<dis[c][d]){ dis[c][d]=dis[a][b]+w[b][c]+w[c][d]+w[d][a]-1; if(id[c][d]==0)id[c][d]=q.push(node{c,d,dis[c][d]}); else q.modify(id[c][d],node{c,d,dis[c][d]}); } } } cout<<dis[2][2]; return 0; } ```