信息学奥赛一本通(1197:山区建小学)
1197:山區建小學
時間限制: 1000 ms ??? ??? 內存限制: 65536 KB
提交數: 3900 ??? 通過數: 2713
【題目描述】
? ? ? ? 政府在某山區修建了一條道路,恰好穿越總共m個村莊的每個村莊一次,沒有回路或交叉,任意兩個村莊只能通過這條路來往。已知任意兩個相鄰的村莊之間的距離為di(為正整數),其中,0<i<m。為了提高山區的文化素質,政府又決定從m個村中選擇n個村建小學(設0<n≤m<500)。請根據給定的m、n以及所有相鄰村莊的距離,選擇在哪些村莊建小學,才使得所有村到最近小學的距離總和最小,計算最小值。
【輸入】
第1行為m和n,其間用空格間隔
第2行為m?1個整數,依次表示從一端到另一端的相鄰村莊的距離,整數之間以空格間隔。
例如:
10 3 2 4 6 5 2 4 3 1 3表示在10個村莊建3所學校。第1個村莊與第2個村莊距離為2,第2個村莊與第3個村莊距離為4,第3個村莊與第4個村莊距離為6,...,第9個村莊到第10個村莊的距離為3。
【輸出】
各村莊到最近學校的距離之和的最小值。
【輸入樣例】
10 2 3 1 3 1 1 1 1 1 3【輸出樣例】
18【分析】
? ? ? ? 這道題是區間DP,放置到遞推算法中有些牽強,詳細分析可以參見:
https://www.cnblogs.com/TFLS-gzr/p/10809257.html。
? ? ? ? 確定子問題:問題是m個村莊中選n個建小學,那么我們可以考慮在前m個村莊中選n-1個的情況,可以考慮在前m個村莊中選n-2個的情況,也可以考慮在前m-1個村莊中選n-1個的情況,……這些都是原問題的子問題。
設計狀態:按照剛才所劃分的子問題,我們可以自然的想到狀態是什么,定義數組f[ i ][ j ]為當在前 i 個村莊中建立 j 個小學的最小路程和,那么原問題(在m個村莊中選n個建小學)的答案就是f[ m ][ n ],這樣問題就涉及好了。
階段:村莊編號 m
狀態:小學編號 n
決策:建?在哪建?
策略:最小路徑和
目標:f[m][n]
狀態轉移方程:首先假裝我們已經算出了每兩個村莊之間建立一個小學的最短距離和,并把這些數據存在數組c[ i ][ j ],那么我們就知道了村莊 i 到村莊 j 這個區間內建一個小學的最短距離和,先不要考慮我們是怎么算出來的;
邊界:f[i][1]=c[1][i],前 i 個村莊中建一個小學時,都等于1到第 i 個村莊只建一個學校的最短距離和。
【參考代碼】
#include <stdio.h> #include <math.h> #define N 1010 int a[N][N]; //村莊i到村莊j間的最短距離 int c[N][N]; //村莊i到村莊j這個區間內建一個小學的最短距離和 int f[N][N]; //前i個村莊中建立j個小學的最小路程和 int min(int x,int y) {return x < y ? x : y; } int main() {int m,n,i,j,k,mid;scanf("%d%d",&m,&n);for(i=1;i<m;i++)scanf("%d",&a[i][i+1]);for(i=1;i<=m;i++)for(j=i+1;j<=m;j++)a[i][j]=a[j][i]=a[i][j-1]+a[j-1][j];for(i=1;i<=m;i++)for(j=i+1;j<=m;j++){mid=(i+j)/2;for(k=i;k<=j;k++)c[i][j]+=a[k][mid];}for(i=1;i<=m;i++)f[i][1]=c[1][i];for(i=1;i<=m;i++)for(j=2;j<=n;j++){f[i][j]=999999;for(k=j-1;k<=i;k++){f[i][j]=min(f[i][j],f[k][j-1]+c[k+1][i]);}}printf("%d\n",f[m][n]);return 0; }http://ybt.ssoier.cn:8088/problem_show.php?pid=1197
?
總結
以上是生活随笔為你收集整理的信息学奥赛一本通(1197:山区建小学)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 信息学奥赛一本通 1069:乘方计算 |
- 下一篇: 信息学奥赛一本通(1220:单词接龙)