hdu5834(树形dp)

去年蓝桥杯结束以后基本就没有在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]);
		}
	}

}









猜你喜欢

转载自blog.csdn.net/lixiaomu2/article/details/80038618
今日推荐