#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string.h>
#define N 6005 //樹形dp POJ2342
using namespace std;
struct tree
{
int child, father, brother; //結點的子節點,父親結點, 兄弟結點
int present, non_present; //present表示此人到場的最大價值, non_present表示此人不到場的最大價值
void init()
{
child=father=brother=non_present=0; //初始化
}
}p[N];
void dfs(int x)
{
int k=p[x].child;
while(k)
{
dfs(k); //深搜下去到子節點,從下到上
p[x].present+=p[k].non_present; //狀態轉移方程,x到場的話則加上它的孩子不到場的價值
p[x].non_present+=max(p[k].present, p[k].non_present);//x不到場的話則加上他的孩子(到場或不到場---孩子和brother之間也不受影響)的最大值
k=p[k].brother; //x的孩子還包括(x的孩子的brother)
}
return ;
}
int main()
{
int n, t, l, k;
while(scanf("%d", &n)!=EOF)
{
for(t=1; t<=n; ++t)
{
scanf("%d", &p[t].present);
p[t].init();
}
while(scanf("%d%d", &l, &k)!=EOF&&l+k!=0)
{
p[l].father=k;
p[l].brother=p[k].child; //一個接一個,記錄上一個
p[k].child=l; //可以從這裏逐漸往上推,推出k所有的child
}
for(t=1; t<=n; ++t)
{
if(!p[t].father) //從根節點出發
{
dfs(t); //搜索並記錄下來
printf("%d\n", max(p[t].present, p[t].non_present));
break;
}
}
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#define LL long long
#define inf 0x7fffffff
#define N 250
using namespace std; //hdu2412 樹形dp及最佳方案是否唯一
int dp[N][2], dup[N][2]; //dp[n][m]中m爲0表示不來,m爲1表示來, dup[n][m]表示最佳的方案是不是唯一的,dup[n][m]中m爲0表示不唯一,m爲1表示唯一
map<string, int> s;
/*
題意:n個人形成一個關係樹,每個節點代表一個人,節點的根表示這個人的唯一的直接上司,只有根沒有上司。
要求選取一部分人出來,使得每2個人之間不能有直接的上下級的關係,求最多能選多少個人出來,並且求出獲得最大人數的選人方案是否唯一。
思路:樹形dp
dp[x][0]+=max(dp[k][0], dp[k][1]); k是x的孩子
dp[x][1]+=dp[k][0];
*/
struct node
{
int pre, brother, son;
void init()
{
pre=brother=son=0;
return ;
}
}p[N];
void dfs(int x)
{
int k=p[x].son;
dup[x][0]=dup[x][1]=1; //注意初始化每個人來和不來都是唯一的方案
while(k)
{
dfs(k);
dp[x][0]+=max(dp[k][0], dp[k][1]);
dp[x][1]+=dp[k][0];
if((dp[k][0]>dp[k][1]&&!dup[k][0])||(dp[k][0]<dp[k][1]&&!dup[k][1])||dp[k][0]==dp[k][1])
dup[x][0]=0;
if(!dup[k][0])
dup[x][1]=0;
k=p[k].brother;
}
return ;
}
int main()
{
int n, t, j, k, id1, id2;
string s1, s2;
while(scanf("%d", &n)&&n)
{
s.clear();
memset(dp, 0, sizeof(dp));
for(t=1; t<=n; ++t)
{
p[t].init();
dp[t][1]=1;
}
k=1;
cin>>s1;
s[s1]=k++;
for(t=1; t<n; ++t)
{
cin>>s1>>s2;
if(!s[s1])
{
s[s1]=k++;
}
if(!s[s2])
{
s[s2]=k++;
}
id1=s[s1];
id2=s[s2];
p[id1].pre=id2;
p[id1].brother=p[id2].son;
p[id2].son=id1;
}
dfs(1);
int ans, flag=0;
if(dp[1][0]>dp[1][1])
{
ans=dp[1][0];
if(dup[1][0]==1)
flag=1;
}
else if(dp[1][0]<dp[1][1])
{
ans=dp[1][1];
if(dup[1][1]==1)
flag=1;
}
else
{
ans=dp[1][0];
}
printf("%d ", ans);
if(flag)
{
printf("Yes\n");
}
else printf("No\n");
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#define LL long long
#define inf 0x7fffffff
#define N 2500
using namespace std; //hdu1054 樹形dp
int dp[N][2];
struct node
{
int pre, brother, son;
void init()
{
pre=brother=son=0;
return ;
}
}p[N];
void dfs(int x)
{
int k=p[x].son;
while(k)
{
dfs(k);
dp[x][0]+=dp[k][1];
dp[x][1]+=min(dp[k][0], dp[k][1]);
k=p[k].brother;
}
return ;
}
int main()
{
int n, t, a, k, b;
while(scanf("%d", &n)!=EOF)
{
memset(dp, 0, sizeof(dp));
for(t=1; t<=n; ++t)
{
p[t].init();
dp[t][1]=1;
}
for(t=0; t<n; ++t)
{
scanf("%d:(%d)", &a, &k); //注意這裏編號可以從0開始,所以每一個編號都要加1
a++;
while(k--)
{
scanf("%d", &b);
b++;
p[b].pre=a;
p[b].brother=p[a].son;
p[a].son=b;
}
}
int ans;
for(t=1; t<=n; ++t)
{
if(!p[t].pre)
{
dfs(t);
ans=min(dp[t][0], dp[t][1]);
break;
}
}
printf("%d\n", ans);
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#define LL long long
#define inf 0x7fffffff
#define N 10100
using namespace std; //hdu 2196 樹形dp
int vis[N], pre[N], dp[N][3]; //dp[n][m]中n是節點編號, m爲0表示從下到上節點的最大值, m爲1表示從小到上第2大值, m爲2表示從上到下的最大值
/*
題意:給你一棵樹,求樹上各個節點到其他節點的距離中的最大值
思路:先用鄰接表建樹,樹形dp
*/
struct node
{
int v, next, w; //表示的是一條邊
}p[N<<1];
void init()
{
memset(pre, -1, sizeof(pre));
memset(dp, 0, sizeof(dp));
memset(vis, 0, sizeof(vis));
}
void dfs1(int x) //從下到上
{
vis[x]=1;
int j, t, biggest, bigger;
biggest=bigger=0;
for(j=pre[x]; j!=-1; j=p[j].next)
{
if(vis[p[j].v]) //之前訪問過的祖先
continue;
dfs1(p[j].v);
if(dp[p[j].v][0]+p[j].w>biggest)
{
bigger=biggest;
biggest=dp[p[j].v][0]+p[j].w;
}
else if(dp[p[j].v][0]+p[j].w>bigger)
{
bigger=dp[p[j].v][0]+p[j].w;
}
dp[x][0]=biggest;
dp[x][1]=bigger;
}
return ;
}
void dfs2(int x) //從上到下
{
vis[x]=1;
int t, j, son;
for(j=pre[x]; j!=-1; j=p[j].next)
{
son=p[j].v;
if(vis[son])continue;
dp[son][2]=(dp[son][0]+p[j].w==dp[x][0]?dp[x][1]:dp[x][0])+p[j].w; //表示這個節點的父親節點下的其他分支的最大值
dp[son][2]=max(dp[son][2], dp[x][2]+p[j].w); //父親節點之上的最大值
dfs2(p[j].v);
}
}
int main()
{
int n, t, j, k, a, b;
while(~scanf("%d", &n))
{
k=0;
init();
for(t=2; t<=n; ++t)
{
scanf("%d%d", &a, &b); //無向圖
p[k].v=t;
p[k].w=b;
p[k].next=pre[a];
pre[a]=k++;
p[k].v=a;
p[k].w=b;
p[k].next=pre[t];
pre[t]=k++;
}
dfs1(1); //從下到上遞推,求出dp[N][0]和dp[N][1]
memset(vis, 0, sizeof(vis));
dfs2(1); //從上到下
for(t=1; t<=n; ++t)
printf("%d\n", max(dp[t][0], dp[t][2]));
}
return 0;
}