最优连通子集
众所周知,我们可以通过直角坐标系把平面上的任何一个点P用一个有序数对(x, y)来唯一表示,如果x, y都是整数,我们就把点P称为整点,否则点P称为非整点。我们把平面上所有整点构成的集合记为W。
定义1 两个整点P1(x1, y1), P2(x2, y2),若|x1-x2| + |y1-y2| = 1,则称P1, P2相邻,记作P1~P2,否则称P1, P2不相邻。
定义 2 设点集S是W的一个有限子集,即S = {P1, P2,..., Pn}(n >= 1),其中Pi(1 <= i <= n)属于W,我们把S称为整点集。
定义 3 设S是一个整点集,若点R, T属于S,且存在一个有限的点序列Q1, Q2, ?, Qk满足:
1. Qi属于S(1 <= i <= k);
2. Q1 = R, Qk = T;
3. Qi~Qi + 1(1 <= i <= k-1),即Qi与Qi + 1相邻;
4. 对于任何1 <= i < j <= k有Qi ≠ Qj;
我们则称点R与点T在整点集S上连通,把点序列Q1, Q2,..., Qk称为整点集S中连接点R与点T的一条道路。
定义4 若整点集V满足:对于V中的任何两个整点,V中有且仅有一条连接这两点的道路,则V称为单整点集。
定义5 对于平面上的每一个整点,我们可以赋予它一个整数,作为该点的权,于是我们把一个整点集中所有点的权的总和称为该整点集的权和。
我们希望对于给定的一个单整点集V,求出一个V的最优连通子集B,满足:
1. B是V的子集
2. 对于B中的任何两个整点,在B中连通;
3. B是满足条件(1)和(2)的所有整点集中权和最大的。
Input
第1行是一个整数N(2 <= N <= 1000),表示单整点集V中点的个数;
以下N行中,第i行(1 <= i <= N)有三个整数,Xi, Yi, Ci依次表示第i个点的横坐标,纵坐标和权。同一行相邻两数之间用一个空格分隔。-10^6 <= Xi, Yi <= 10^6;-100 <= Ci <= 100。
Output
仅一个整数,表示所求最优连通集的权和。
Sample Input
5
0 0 -2
0 1 1
1 0 1
0 -1 1
-1 0 1
3
1 0 1
0 0 -3
0 1 8
Sample Output
2
Source
题目类型:树形DP
算法分析:根据题目中所描述的单连通集的概念可知,最后建出来的图是一个无根树。可以进行一次树形DP,每次累加当前节点的所有子节点中点权大于零的点权值并依据子节点情况更新maxval
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
/************************************************* Author :supermaker Created Time :2016/3/24 8:31:45 File Location :C:\Users\abcd\Desktop\TheEternalPoet **************************************************/ #pragma comment(linker, "/STACK:102400000,102400000") #include <set> #include <bitset> #include <list> #include <map> #include <stack> #include <queue> #include <deque> #include <string> #include <vector> #include <ios> #include <iostream> #include <fstream> #include <sstream> #include <iomanip> #include <algorithm> #include <utility> #include <complex> #include <numeric> #include <functional> #include <cmath> #include <ctime> #include <climits> #include <cstdarg> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <cassert> using namespace std; #define CFF freopen ("aaa.txt", "r", stdin) #define CPPFF ifstream cin ("aaa.txt") #define DB(ccc) cout << #ccc << " = " << ccc << endl #define PB push_back #define MP(A, B) make_pair(A, B) typedef long long LL; typedef unsigned long long ULL; typedef double DB; typedef pair <int, int> PII; typedef pair <int, bool> PIB; const int INF = 0x7F7F7F7F; const int MOD = 1e9 + 7; const double EPS = 1e-10; const double PI = 2 * acos (0.0); const int maxn = 1000 + 66; int xx[maxn], yy[maxn], ww[maxn], maxval, n; bool edge[maxn][maxn], vis[maxn]; int dfs (int rt) { vis[rt] = true; int tt = 0, cnt = 0; for (int i = 1; i <= n; i++) if (i != rt && edge[rt][i] && !vis[i]) { int v = dfs (i); if (v > 0) { tt += v; cnt++; } } if (cnt >= 2) maxval = max (maxval, tt + ww[rt]); else { maxval = max (maxval, tt + ww[rt]); maxval = max (maxval, tt); } return tt + ww[rt]; } int main() { //CFF; //CPPFF; while (scanf ("%d", &n) != EOF) { for (int i = 1; i <= n; i++) scanf ("%d%d%d", &xx[i], &yy[i], &ww[i]); memset (edge, false, sizeof (edge)); for (int i = 1; i <= n; i++) for (int j = i + 1; j <= n; j++) if (abs (xx[i] - xx[j]) + abs (yy[i] - yy[j]) == 1) edge[i][j] = edge[j][i] = true; maxval = -INF; memset (vis, false, sizeof (vis)); maxval = max (maxval, dfs (1)); printf ("%d\n", maxval); } return 0; } |
- « 上一篇:poj1613
- poj2607:下一篇 »