poj1639 Picnic Planning
这题首先感慨下, 我的代码真的是太垃圾了。
其实这题的思想是:堆+prime+dp, 来做的, 我看了下我的代码总是冗余很重, 所以直接去掉堆了。
这题的想法是限制的最小生成树。
1.把所有的字母转化成图。
2.去掉定点Park, 然后建最小生成树。 同时在每一个最小生成树连一条到定点的边(这条边到该树最短)。
3.对每颗最小生成树进行dfs
4.枚举定点的每一个边。选出差值最大的那条边然后修改最小生成树, 之后再从这点出发, dfs。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<stdio.h> #include<string.h> #define maxn 23 #define inf 0x7ffffff int map[maxn][maxn], e[maxn][maxn], edge[maxn][maxn]; int dist[maxn], visit[maxn]; int sum_val; int n, m; char name[maxn][11]; int flag[maxn], pre[maxn], last[maxn][maxn]; int name_count; int edge_visit[maxn]; int k_th; int flag_point; int find() { int i ; for (i = 0; i <= name_count; i ++) { if (strcmp(name[i], name[name_count + 1]) == 0) { return i; } } name_count ++; return i; } inline void add_map(int x, int y, int val) { map[x][22] ++; map[x][map[x][22]] = y; map[y][22] ++; map[y][map[y][22]] = x; e[x][y] = e[y][x] = val; } void init() { int i, x, y, val; memset(map, 0, sizeof(map)); memset(e, 0, sizeof(e)); memset(last, 0, sizeof(last)); name_count = 0; sum_val = 0; flag_point = 0; strcpy(name[0], "Park"); for (i = 0; i < m; i++) { scanf("%s", name[name_count + 1]); x = find(); scanf("%s", name[name_count + 1]); y = find(); scanf("%d", &val); add_map(x, y, val); } scanf("%d", &k_th); } void add_edge(int x, int y) { edge[x][22] ++; edge[x][edge[x][22]] = y; edge[y][22] ++ ; edge[y][edge[y][22]] = x; } void check(int parent, int current) { for (int i = 1; i <= map[current][22]; i ++) { if (parent != map[current][i] && map[current][i] != 0 && edge_visit[map[current][i]] == 0) { add_edge(current, map[current][i]); } } for (int i = 1; i <= map[current][22]; i ++) { if (parent != map[current][i] && map[current][i] != 0 && edge_visit[map[current][i]] == 0 ) { edge_visit[map[current][i]] = 1; check(current, map[current][i]); } } } inline void judge(int &min_point, int &min_val, int point) { if (e[point][0] > 0 && e[point][0] < min_val) { min_point = point; min_val = e[point][0]; } } inline void add_last(int x, int y) { last[x][22] ++; last[x][last[x][22]] = y; last[y][22] ++; last[y][last[y][22]] = x; } void prime(int start) { int i, j, k, max_val, min_val; int min_point; min_val = inf; for (i = 1; i <= name_count; i ++) { dist[i] = inf; pre[i] = start; } for (i = 1; i <= edge[start][22]; i ++) { dist[edge[start][i]] = e[start][edge[start][i]]; } dist[start] = inf; visit[start] = 1; judge(min_point, min_val, start); for (i = 2; i <= name_count; i ++) { max_val = inf; k = 0; for (j = 1; j <= name_count; j ++) { if (visit[j] == 0 && dist[j] < max_val) { k = j; max_val = dist[j]; } } if (max_val == inf) { break; } judge(min_point, min_val, k); visit[k] = 1; add_last(pre[k], k); sum_val += max_val; for (j = 1; j <= edge[k][22]; j ++) { int x = edge[k][j]; if (visit[x] == 0 && dist[x] > e[k][x] && x != 0) { dist[x] = e[k][x]; pre[x] = k; } } } add_last(0, min_point); sum_val += e[0][min_point]; flag[min_point] = 1; return; } struct node { int left, right, val; }dp[maxn][maxn]; int dp_point; inline void add_dp(int left, int right, int val, int dp_right) { dp[dp_point][dp_right].left = left; dp[dp_point][dp_right].right = right; dp[dp_point][dp_right].val = val; dp[flag_point][dp_right].val = 0; //printf("%d %d\n", flag_point, dp_right); } void dfs(int parent, int current, int left, int right, int val) { //dp[flag_point][current].val = 0; for (int i = 1; i <= last[current][22]; i ++) { int x = last[current][i]; if (x != parent) { if (val < e[x][current]) { add_dp(x, current, e[x][current], x); dfs(current, x, current, x, e[x][current]); } else { add_dp(left, right, val, x); dfs(current, x, left, right, val); } } } } void del(int left, int right) { int k = 1; while (last[left][k] != right) k ++; while (k < last[left][22]) last[left][k] = last[left][k + 1], k ++; k = 1; while (last[right][k] != left) k ++; while (k < last[right][22]) last[right][k] = last[right][k + 1], k ++; last[left][22]--; last[right][22] --; } void funs() { memset(visit, 0, sizeof(visit)); memset(last, 0, sizeof(last)); memset(&dp, 0, sizeof(dp)); for (int i = 1; i <= name_count; i ++) { if (visit[i] == 0) { memset(edge, 0, sizeof(edge)); memset(edge_visit, 0, sizeof(edge_visit)); edge_visit[i] = 1; check(0, i); prime(i); } } int count = 0; for (int i = 1; i <= last[0][22]; i ++) { dp_point = last[0][i]; dfs(0, last[0][i], 0, 0, 0); count ++; } for (int i = count + 1; i <= k_th && i <= map[0][22]; i ++) { int count_val, count_left, count_right; int count_point; count_val = 0; for (int j = 1; j <= map[0][22]; j ++) { if (flag[map[0][j]] == 0) { for (int k = 1; k <= last[0][22]; k ++) { int val = dp[last[0][k]][map[0][j]].val; if (val > 0 && val - e[0][map[0][j]] > count_val ) { count_val = val - e[0][map[0][j]]; count_left = dp[last[0][k]][map[0][j]].left; count_right = dp[last[0][k]][map[0][j]].right; count_point = map[0][j]; flag_point = last[0][k]; } } } } //printf("%d %d %d %d \n", count_left, count_right, count_point, count_val); if (count_val == 0) { break; } sum_val -= count_val; del(count_left, count_right); add_last(0, count_point); flag[count_point] = 1; dp_point = count_point; dfs(0, count_point, 0, 0, 0); } printf("Total miles driven: %d\n", sum_val); return; } int main() { while (scanf("%d", &m) != EOF) { init(); funs(); } return 0; }