1. 程式人生 > >BZOJ1040 基環森林 找環+基礎樹形DP

BZOJ1040 基環森林 找環+基礎樹形DP

pri script 矛盾 add 順序 自己 任務 樹形dp 按順序

1040: [ZJOI2008]騎士

Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 4752 Solved: 1831
[Submit][Status][Discuss]

Description

  Z國的騎士團是一個很有勢力的組織,幫會中匯聚了來自各地的精英。他們劫富濟貧,懲惡揚善,受到社會各
界的贊揚。最近發生了一件可怕的事情,邪惡的Y國發動了一場針對Z國的侵略戰爭。戰火綿延五百裏,在和平環境
中安逸了數百年的Z國又怎能抵擋的住Y國的軍隊。於是人們把所有的希望都寄托在了騎士團的身上,就像期待有一
個真龍天子的降生,帶領正義打敗邪惡。騎士團是肯定具有打敗邪惡勢力的能力的,但是騎士們互相之間往往有一
些矛盾。每個騎士都有且僅有一個自己最厭惡的騎士(當然不是他自己),他是絕對不會與自己最厭惡的人一同出
征的。戰火綿延,人民生靈塗炭,組織起一個騎士軍團加入戰鬥刻不容緩!國王交給了你一個艱巨的任務,從所有
的騎士中選出一個騎士軍團,使得軍團內沒有矛盾的兩人(不存在一個騎士與他最痛恨的人一同被選入騎士軍團的
情況),並且,使得這支騎士軍團最具有戰鬥力。為了描述戰鬥力,我們將騎士按照1至N編號,給每名騎士一個戰
鬥力的估計,一個軍團的戰鬥力為所有騎士的戰鬥力總和。

Input

  第一行包含一個正整數N,描述騎士團的人數。接下來N行,每行兩個正整數,按順序描述每一名騎士的戰鬥力
和他最痛恨的騎士。

Output

  應包含一行,包含一個整數,表示你所選出的騎士軍團的戰鬥力。

Sample Input

3
10 2
20 3
30 1

Sample Output

30 http://blog.csdn.net/popoqqq/article/details/39748135 先膜為敬 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1001001;
struct node
{
int to,next;
} edge[maxn<<1];
int head[maxn],tot=1,value[maxn],U,V,E;
long long f[maxn][2];
bool vis[maxn];
void add(int u,int v)
{
edge[++tot].to=v;
edge[tot].next=head[u];
head[u]=tot;
}
void dfs(int u,int from)
{
vis[u]=1;
for(int i=head[u]; i; i=edge[i].next)
{
if((i^1)==from) continue; //此處不能用父節點判斷,因為有環的存在

int v=edge[i].to;
if(vis[v])
{
U=u;
V=v;
E=i;
continue;
}
dfs(v,i);
}
}
void dp(int u,int from,int ban)
{
f[u][0]=0;
f[u][1]=value[u];
for(int i=head[u]; i; i=edge[i].next)
{
if((i^1)==from||i==ban||(i^1)==ban) continue;
int v=edge[i].to;
dp(v,i,ban);
f[u][0]+=max(f[v][1],f[v][0]);
f[u][1]+=f[v][0];
}
}
int main()
{
int t,v;
long long ans=0;
scanf("%d",&t);
for(int i=1; i<=t; ++i)
{
scanf("%d%d",&value[i],&v);
add(i,v);
add(v,i);
}
for(int i=1; i<=t; ++i)
if(!vis[i])
{
dfs(i,0);
dp(U,0,E);
long long temp=f[U][0];
dp(V,0,E);
temp=max(f[V][0],temp);
ans+=temp;
}
printf("%lld\n",ans);
}

BZOJ1040 基環森林 找環+基礎樹形DP