去年蓝桥杯结束以后基本就没有在oj上刷题了,最近突然被老师拉去要打JSCPC(江苏省大学生程序设计大赛),只能在hdu上找找以前ccpc的题目刷刷,顺便复习复习(而且估计也没时间刷那种比较水的题了)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5834
参考题解:http://www.cnblogs.com/WABoss/p/5771931.html
题意和一些分析上面的题解有,里面给出的是c++的实现。我感觉这个题解已经算是网上对于这道题分析里面最详细的了,但是我其实还是不太理解,硬着头皮把题解里面的c++代码翻译成java然后再研究,大致才有了感觉,大体如下(很多还是实在说不清楚,需要自己在草稿纸上画画体会):
- dp_down[0/1][u]:u结点往其为根的子树走,并且不走回来/走回来,能得到的最大权值
- dp_up[0/1][u]:u结点往其父亲向上走,并且不走回来/走回来,能得到的最大权值
关于d_down[0][u]部分的代码
d_down[0][u]=d_down[1][u]=val[u];
for (int i=head[u];i!=-1;i=edges[i].next) {
int v=edges[i].v;
if (v==fa) continue;
dfs1(v, u);
if (d_down[0][v]-2*edges[i].w>0)
d_down[0][u]+=d_down[0][v]-2*edges[i].w;
}
这里v是u的儿子,显然如果沿着v走下去再走回来能够赚钱,那么就要把v为根的这个子树在计算代价时选进去
关于d_down[1][u]部分的代码
int mx=0;
for (int i=head[u];i!=-1;i=edges[i].next) {
int v=edges[i].v;
if (v==fa) continue;
if (d_down[0][v]-2*edges[i].w>0) {
mx=max(mx, (d_down[1][v]-edges[i].w)-(d_down[0][v]-2*edges[i].w));
}
else {
mx=max(mx, d_down[1][v]-edges[i].w);
}
}
d_down[1][u]=d_down[0][u]+mx;
这里着重考虑最后要从哪个儿子v往下走不回来的问题,分两种情况考虑,一种是v在之前求d_down[0][u]的策略
中被用到的情况,一种是没被用到的情况,然后进行讨论,取最大
int mx1=0,mx2=0,tmp;
for (int i=head[u];i!=-1;i=edges[i].next) {
int v=edges[i].v;
if (v==fa) continue;
if (d_down[0][v]-2*edges[i].w>0)
tmp=(d_down[1][v]-edges[i].w)-(d_down[0][v]-2*edges[i].w);
else
tmp=d_down[1][v]-edges[i].w;
if (mx1<tmp) {
mx2=mx1;
mx1=tmp;
}
else if (mx2<tmp) {
mx2=tmp;
}
}
以上代码求了一个最大值一个次大值,在求d_up[1][v]时会使用到
关于d_up[0][v]部分的代码
int v=edges[i].v;
if (v==fa) continue;
int tmp2;
if (d_down[0][v]-2*edges[i].w>0)
tmp2=d_down[0][u]-(d_down[0][v]-2*edges[i].w);
else
tmp2=d_down[0][u];
int mx=max(d_up[0][u]-2*edges[i].w,tmp2-2*edges[i].w);
int tmp3=d_up[0][u]+tmp2-2*edges[i].w-val[u];
mx=max(mx, tmp3);
d_up[0][v]=val[v]+max(0, mx);
这个是对于从v的父亲u,考虑单纯从以u为根的子树往下走再走回u再走回v,单纯u结点往其父亲方向走再走回u再走回v,以及u两个方向都走一遍再回到v这三种情况进行讨论(注意这里从u往下走再走回来是不包括走以v为根的这个子树的情况的)
关于d_up[1][v]部分的代码
if (d_down[0][v]-2*edges[i].w>0)
{
if (mx1==(d_down[1][v]-edges[i].w)-(d_down[0][v]-2*edges[i].w))
tmp=d_down[1][u]-(d_down[1][v]-edges[i].w)+mx2;
else
tmp=d_down[1][u]-(d_down[0][v]-2*edges[i].w);
}
else if (d_down[1][v]-edges[i].w>0)
{
if (mx1==d_down[1][v]-edges[i].w)
tmp=d_down[1][u]-(d_down[1][v]-edges[i].w)+mx2;
else
tmp=d_down[1][u];
}
else tmp=d_down[1][u];
mx=max(d_up[1][u]-edges[i].w, tmp-edges[i].w);
mx=max(mx, max(d_up[0][u]+tmp-edges[i].w-val[u],d_up[1][u]+tmp2-edges[i].w-val[u]));
d_up[1][v]=val[v]+max(0, mx);
这个主要是考虑v走到u以后往其父亲方向走不回来,沿以u为根的子树往下走而且不回来,以及到了u以后先往下走再往上走不回来,以及先往上走再往下走不回来这样四种情况(然后注意对上面最大值和次大值应用的理解~~~)
最后的结果输出(如果我上面写的代码能理解的话,这个结果表示应该也不难理解)
for (int i=1;i<=n;i++)
System.out.println(max(d_up[0][i]+d_down[1][i], d_up[1][i]+d_down[0][i])-val[i]);
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
class Reader{
static BufferedReader reader;
static StringTokenizer tokenizer;
static void init(InputStream input) {
reader=new BufferedReader(new InputStreamReader(input));
tokenizer=new StringTokenizer("");
}
static String next() throws IOException{
while (!tokenizer.hasMoreTokens()) {
tokenizer=new StringTokenizer(reader.readLine());
}
return tokenizer.nextToken();
}
static int nextInt() throws IOException {
return Integer.parseInt(next());
}
}
class Edge{
int v,w,next;
/**
* @param v
* @param w
* @param next
*/
public Edge(int v, int w, int next) {
super();
this.v = v;
this.w = w;
this.next = next;
}
/**
*
*/
public Edge() {
super();
// TODO Auto-generated constructor stub
}
/**
* @return the v
*/
public int getV() {
return v;
}
/**
* @param v the v to set
*/
public void setV(int v) {
this.v = v;
}
/**
* @return the w
*/
public int getW() {
return w;
}
/**
* @param w the w to set
*/
public void setW(int w) {
this.w = w;
}
/**
* @return the next
*/
public int getNext() {
return next;
}
/**
* @param next the next to set
*/
public void setNext(int next) {
this.next = next;
}
}
public class Main {
static int t,n,u,v,c,cnt;
static int head[],val[];
static int maxn=200000;
static Edge edges[]=new Edge[2*maxn];
static int d_down[][]=new int[3][maxn];
static int d_up[][]=new int[3][maxn];
static int max(int a,int b) {
return a>b?a:b;
}
static void dfs1(int u,int fa) {
d_down[0][u]=d_down[1][u]=val[u];
for (int i=head[u];i!=-1;i=edges[i].next) {
int v=edges[i].v;
if (v==fa) continue;
dfs1(v, u);
if (d_down[0][v]-2*edges[i].w>0)
d_down[0][u]+=d_down[0][v]-2*edges[i].w;
}
int mx=0;
for (int i=head[u];i!=-1;i=edges[i].next) {
int v=edges[i].v;
if (v==fa) continue;
if (d_down[0][v]-2*edges[i].w>0) {
mx=max(mx, (d_down[1][v]-edges[i].w)-(d_down[0][v]-2*edges[i].w));
}
else {
mx=max(mx, d_down[1][v]-edges[i].w);
}
}
d_down[1][u]=d_down[0][u]+mx;
}
static void dfs2(int u,int fa) {
int mx1=0,mx2=0,tmp;
for (int i=head[u];i!=-1;i=edges[i].next) {
int v=edges[i].v;
if (v==fa) continue;
if (d_down[0][v]-2*edges[i].w>0)
tmp=(d_down[1][v]-edges[i].w)-(d_down[0][v]-2*edges[i].w);
else
tmp=d_down[1][v]-edges[i].w;
if (mx1<tmp) {
mx2=mx1;
mx1=tmp;
}
else if (mx2<tmp) {
mx2=tmp;
}
}
for (int i=head[u];i!=-1;i=edges[i].next) {
int v=edges[i].v;
if (v==fa) continue;
int tmp2;
if (d_down[0][v]-2*edges[i].w>0)
tmp2=d_down[0][u]-(d_down[0][v]-2*edges[i].w);
else
tmp2=d_down[0][u];
int mx=max(d_up[0][u]-2*edges[i].w,tmp2-2*edges[i].w);
int tmp3=d_up[0][u]+tmp2-2*edges[i].w-val[u];
mx=max(mx, tmp3);
d_up[0][v]=val[v]+max(0, mx);
if (d_down[0][v]-2*edges[i].w>0)
{
if (mx1==(d_down[1][v]-edges[i].w)-(d_down[0][v]-2*edges[i].w))
tmp=d_down[1][u]-(d_down[1][v]-edges[i].w)+mx2;
else
tmp=d_down[1][u]-(d_down[0][v]-2*edges[i].w);
}
else if (d_down[1][v]-edges[i].w>0)
{
if (mx1==d_down[1][v]-edges[i].w)
tmp=d_down[1][u]-(d_down[1][v]-edges[i].w)+mx2;
else
tmp=d_down[1][u];
}
else tmp=d_down[1][u];
mx=max(d_up[1][u]-edges[i].w, tmp-edges[i].w);
mx=max(mx, max(d_up[0][u]+tmp-edges[i].w-val[u],d_up[1][u]+tmp2-edges[i].w-val[u]));
d_up[1][v]=val[v]+max(0, mx);
dfs2(v,u);
}
}
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
Reader.init(System.in);
t=Reader.nextInt();
head=new int[maxn+1];
for (int casenum=1;casenum<=t;casenum++) {
n=Reader.nextInt();
val=new int[n+1];
cnt=0;
for (int i=1;i<=n;i++)
val[i]=Reader.nextInt();
for (int i=1;i<=n;i++)
head[i]=-1;
for (int i=1;i<n;i++) {
u=Reader.nextInt();
v=Reader.nextInt();
c=Reader.nextInt();
cnt++;
edges[cnt]=new Edge(v,c,head[u]);
head[u]=cnt;
cnt++;
edges[cnt]=new Edge(u,c,head[v]);
head[v]=cnt;
}
dfs1(1, 1);
d_up[0][1]=d_up[1][1]=val[1];
dfs2(1,1);
System.out.println("Case #"+casenum+":");
for (int i=1;i<=n;i++)
System.out.println(max(d_up[0][i]+d_down[1][i], d_up[1][i]+d_down[0][i])-val[i]);
}
}
}