uva 662 (经典DP邮局问题)
2015-03-17 16:06
344 查看
题意:
给在一条直线上的n个汉堡店,以及每个汉堡店在x轴上的坐标。
求建m个供应产,使得每个汉堡店到m个供应产的距离和最小。
解析:
经典的邮局dp问题。
首先需要知道到达几个村庄的最小距离和是这几个村庄的坐标中点。
先用一个遍历找出所有i j之间的所有最小距离,然后再dp。
状态转移方程:
dp[ i ] [ j ] = min ( dp[ i ] [ j ] , dp[ i - 1 ] [ k ] + dis[ k + 1 ] [ j ] )
dp[ i ] [ j ] 表示在j个村庄内,建第i个邮局的最小距离。
dp[ i - 1 ] [ k ] + dis[ k + 1 ] [ j ] 表示得的是在 k + 1 到 j 范围内再建一个邮局的总花费。
路径记录下的是k的值,即为下一段邮局管辖范围内的开头村庄坐标值,再知道此段范围末尾的村庄坐标值,就可以算出邮局的地点。
代码:
给在一条直线上的n个汉堡店,以及每个汉堡店在x轴上的坐标。
求建m个供应产,使得每个汉堡店到m个供应产的距离和最小。
解析:
经典的邮局dp问题。
首先需要知道到达几个村庄的最小距离和是这几个村庄的坐标中点。
先用一个遍历找出所有i j之间的所有最小距离,然后再dp。
状态转移方程:
dp[ i ] [ j ] = min ( dp[ i ] [ j ] , dp[ i - 1 ] [ k ] + dis[ k + 1 ] [ j ] )
dp[ i ] [ j ] 表示在j个村庄内,建第i个邮局的最小距离。
dp[ i - 1 ] [ k ] + dis[ k + 1 ] [ j ] 表示得的是在 k + 1 到 j 范围内再建一个邮局的总花费。
路径记录下的是k的值,即为下一段邮局管辖范围内的开头村庄坐标值,再知道此段范围末尾的村庄坐标值,就可以算出邮局的地点。
代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cstring> #include <cmath> #include <stack> #include <vector> #include <queue> #include <map> #define LL long long using namespace std; const int inf = 0x3f3f3f3f; const int maxn = 200 + 10; const int maxm = 30 + 10; int dp[maxm][maxn]; int path[maxn][maxn]; int dis[maxn][maxn]; int x[maxn]; void print_path(int i, int j) { if (i <= 0) return; int u = path[i][j]; print_path(i - 1, u); if (u + 1 == j) printf("Depot %d at restaurant %d serves restaurant %d\n", i, (u + 1 + j) >> 1, u + 1); else printf("Depot %d at restaurant %d serves restaurants %d to %d\n", i, (u + 1 + j) >> 1, u + 1, j); } int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); #endif // LOCAL int n, m; int ca = 1; while (~scanf("%d%d", &n, &m)) { if (n == 0 && m == 0) break; memset(dp, inf, sizeof(dp)); memset(dis, 0, sizeof(dis)); memset(path, 0, sizeof(path)); memset(x, 0, sizeof(x)); for (int i = 1; i <= n; i++) { scanf("%d", &x[i]); } for (int i = 1; i <= n; i++) { for (int j = i; j <= n; j++) { int mi = (i + j) >> 1; for (int k = i; k <= j; k++) dis[i][j] += abs(x[k] - x[mi]); } } // for (int i = 1; i <= n; i++) { dp[1][i] = dis[1][i]; } for (int i = 2; i <= m; i++)//youju { for (int j = 1; j <= n; j++)//cunzhuan { for (int k = 1; k < j; k++) { int t = dp[i - 1][k] + dis[k + 1][j]; if (t < dp[i][j]) { dp[i][j] = t; path[i][j] = k; } } } } printf("Chain %d\n", ca++); print_path(m, n); printf("Total distance sum = %d\n\n", dp[m] ); } return 0; }
相关文章推荐
- uva 116 Unidirectional TSP 单向TSP 问题,经典dP(路径输出注意规划方向)
- HDU 2069 & UVA 674 Coin Change(换硬币 dp 入门经典水题,背包问题)
- 邮局--dp经典问题
- Poj Post Office 【DP】经典邮局问题
- ♥Vijos 1242-邮局问题【经典DP】
- UVa 571 Jugs(经典倒水问题)
- uva_662 - Fast Food( 区间DP )
- poj1157(花店问题+经典DP)
- 【DP】经典问题解析
- 经典DP之投资者问题
- 入门经典 DP 0-1背包问题
- UVa 10891 Game of Sum(经典博弈区间DP)
- ZOJ1733 POJ1458 Common Subsequence,经典DP问题
- uva 662 Fast Food (dp)
- UVA624(dp记录路径问题)
- 【转】POJ 1159 Palindrome【经典的DP回文问题】
- UVa 10603 - Fill,经典倒水问题+隐式图搜索+dfs
- 0-1背包问题入门小结 动态规划(DP)经典题目 POJ324 POJ1276
- UVa 10069 Distinct Subsequences(经典DP)
- POJ 3280 Cheapest Palindrome【DP之经典回文问题】