285. [NOI1999] 最優連通子集
★☆ 輸入文件:subset.in
輸出文件:subset.out
簡單對比時間限制:1 s 內存限制:128 MB
衆所周知,我們可以通過直角座標系把平面上的任何一個點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滿足:
-
- Qi屬於S(1<=i<=k);
- Q1=R,Qk= T;
- Qi~Qi+1(1<=i<=k-1),即Qi與Qi+1相鄰;
- 對於任何1<=i<j<=k有qi≠qj;< li="">
- 我們則稱點R與點T在整點集S上連通,把點序列Q1,Q2,…,Qk稱爲整點集S中連接點R與點T的一條道路。
定義4
- 若整點集V滿足:對於V中的任何兩個整點,V中有且僅有一條連接這兩點的道路,則V稱爲單整點集。
定義5
- 對於平面上的每一個整點,我們可以賦予它一個整數,作爲該點的權,於是我們把一個整點集中所有點的權的總和稱爲該整點集的權和。
我們希望對於給定的一個單整點集V,求出一個V的最優連通子集B,滿足:
- B是V的子集
- 對於B中的任何兩個整點,在B中連通;
- B是滿足條件(1)和(2)的所有整點集中權和最大的。
輸入
第1行是一個整數N,表示單整點集V中點的個數;
以下N行中,第i行(1<=i<=N)有三個整數,Xi,Yi,Ci依次表示第i個點的橫座標,縱座標和權。同一行相鄰兩數之間用一個空格分隔。
輸出
僅一個整數,表示所求最優連通集的權和。
樣例輸入
5 0 0 -2 0 1 1 1 0 1 0 -1 1 -1 0 1
樣例輸出
2
參數約定
- 2<=N<=1000
- -10^6<=Xi,Yi<=10^6
- -100<=Ci<=100
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define INF 9999999
#define MAX_N 1000
struct Node
{
int x,y;
int v;
int deg;
int link[4];
} sset[MAX_N];
int n;
bool vis[MAX_N];
int val[MAX_N];
bool IsLink(const Node &a,const Node &b)
{
if(abs(a.x-b.x)+abs(a.y-b.y)==1)
{
return true;
}
return false;
}
int dfs(int v)
{
if(vis[v]) return val[v];
vis[v]=true;
int sum=0;
for(int i=0;i<sset[v].deg;i++)
sum+=max(0,dfs(sset[v].link[i]));
sum=max(0,sum+sset[v].v);
return val[v]=sum;
}
int main()
{
freopen("subset.in","r",stdin);
freopen("subset.out","w",stdout);
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&sset[i].x,&sset[i].y,&sset[i].v);
for(int j=0;j<i;j++)
{
if(IsLink(sset[i],sset[j]))
{
sset[i].link[sset[i].deg++]=j;
sset[j].link[sset[j].deg++]=i;
}
}
}
dfs(0);
int maxx;
maxx=-INF;
for(int i=0;i<n;i++)
{
maxx=max(maxx,val[i]);
}
printf("%d\n",maxx);
return 0;
}