题解:P1359 租用游艇

这边是题目传送门喵!

思路

橙题的难度不大,因此本题解主要梳理不同思路。

  1. 由于本题要求的是最短路,那么可以从最短路的角度分析:

    • 本题要求的是点 \(1\)\(n\) 的最短路距离,因此不难想到用单源最短路的模板写过去。当然这里可以写 Dijkstra 也可以写 SPFA 因为毕竟是橙题,数据强度不高。

      一般情况下如果没有负边权就写 Dijkstra 而 SPFA 只在有负边权的时候写。这两种算法可以见此题

    • 注意到数据范围中的 \(1 \leq N \leq 200\),因此可以直接用 Floyd 跑过去。关于 Floyd 的详细信息详见此题

    • 最短路的几种写法都是直接套的模版,代码比较长,这里就不贴出来了。不过我们学习 OI 的时候始终讲求优化算法,同样对于本题也有更容易的算法。

  2. 直接推动态规划的转移方程式。

    • 逆向思维。从 \(n\) 倒推,用 \(f_i\) 存储 \(i\)\(n\) 的距离。边界条件为 \(f_n=0\)。那么显然从 \(n-1\) 遍历到 \(1\),每次的路径都是 \(i \rightarrow j (i<j<n) \rightarrow n\)。由于我们遍历的顺序,我们已知 \(j \rightarrow n\) 这一段的路程。因此转移方程式为:

      \[f_i=min^{j=i+1}_{j<n}(r_{i,j} + f_j) \]

      然后做完了。

        #include<bits/stdc++.h>
        #define ll long long
        #define ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
        using namespace std;
        const int N=205;
        const int inf=1e9;
        int n,r[N][N],f[N];
        signed main(){
        	ios;cin>>n;
            for(int i=1;i<=n;i++){
        		f[i]=inf; // 设为无穷大
            }
            f[n]=0;
        	for(int i=1;i<n;i++){
        		for(int j=i+1;j<=n;j++){
        			cin>>r[i][j];
                    r[j][i]=r[i][j];
        		}
        	}
        	for(int i=n-1;i>=1;i--){
        		for(int j=i+1;j<=n;j++){
        			f[i]=min(f[i],f[j]+r[i][j]);
        		}
        	}
        	cout<<f[1]<<'\n';	
            return 0;
        }
      
    • 考虑从 Floyd 中优化掉一维。用 \(f_i\) 存储 \(1\)\(i\) 的距离。边界条件为 \(f_1=0\)。每次固定 \(i\) 后遍历 \(1\)\(i-1\) 间的点进行松弛操作,也就是:

      \[f_i=min^{j=1}_{j<i}(f_j + r_{j,i}) \]

      其中,由于道路双向可达,\(r_{i,j} = r_{j,i}\)。然后做完了。

      #include<bits/stdc++.h>
      #define ll long long
      #define ios ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
      using namespace std;
      const int N=205;
      const int inf=1e9;
      int n,r[205][205],f[205];
      signed main(){
      	ios;cin>>n;
          for(int i=1;i<=n;i++){
      		f[i]=inf; // 设为无穷大
          }
          f[1]=0;
      	for(int i=1;i<n;i++){
      		for(int j=i+1;j<=n;j++){
      			cin>>r[i][j];
                  r[j][i]=r[i][j];
      		}
      	}
      	for(int i=1;i<=n;i++){
      		for(int j=1;j<i;j++){
      			f[i]=min(f[i],f[j]+r[i][j]);
      		}
      	}
      	cout<<f[n]<<'\n';	
          return 0;
      }
      

写了这么多,这题的多种思路梳理也就结束了。

感谢阅读!完结撒花花!

posted @ 2026-01-19 14:19  Circle_Table  阅读(4)  评论(0)    收藏  举报