zoukankan      html  css  js  c++  java
  • [P4886] 快递员

    考虑在树上选个点rt作为根,并且快递中心就选这儿。计算出所有配送的代价(2*两段之和),设他们的最大值为Max。若此时存在下列情况时,可以判定Max已经为最优解。

    1)存在代价为Max的配送(u,v)且uv分别属于rt的不同的两个“儿子的子树”。
    2)存在代价为Max的配送(u1,v1)(u2,v2)且u1u2分别属于rt的不同的两个“儿子的子树”。
    3)存在代价为Max的配送(u1,v1)(u2,v2)且v1v2分别属于rt的不同的两个“儿子的子树”。

    但是若1)不存在,2)、3)不就是一种情况了吗,滑稽。 概括一下就是当所欲代价为Max的配送的端点所属于的“儿子的子树”不唯一,则已达到最优解,证明就上边那三种情况。

    如果都不满足的话,那么更优的选点应在Max的配送(u,v)的u(=v)所属于的那个“儿子的子树”里。分治下去就好。

    【实现】

    int n,m;
    int head[N],to[M],len[M],last[M];
    int sum,rt,qu[N],qv[N],fiz[N],siz[N],dis[N],bel[N];
    bool ban[N];
    
    void addEdge(int x,int y,int w) {
    	static int cnt=0;
    	to[++cnt]=y;
    	len[cnt]=w;
    	last[cnt]=head[x];
    	head[x]=cnt;
    }
    void getRoot(int x,int pa) {
    	fiz[x]=0,siz[x]=1;
    	for(int i=head[x]; i; i=last[i]) {
    		if(to[i]==pa||ban[to[i]]) continue;
    		getRoot(to[i],x);
    		siz[x]+=siz[to[i]];
    		fiz[x]=max(fiz[x],siz[to[i]]); 
    	}
    	fiz[x]=max(fiz[x],sum-siz[x]);
    	if(fiz[x]<fiz[rt]) rt=x; 
    }
    void getDis(int x,int pa,int id) {
    	bel[x]=id;
    	for(int i=head[x]; i; i=last[i]) {
    		if(to[i]==pa) continue;
    		dis[to[i]]=dis[x]+len[i];
    		getDis(to[i],x,id);
    	}
    }
    int sta[N];
    int solveAt(int x) {
    	if(ban[x]) return 2e9;
    	ban[x]=1,dis[x]=0;
    	for(int i=head[x]; i; i=last[i]) {
    		dis[to[i]]=len[i];
    		getDis(to[i],x,to[i]);
    	}
    	int Max=0,top=0;
    	for(int i=1; i<=m; ++i) {
    		if(Max<dis[qu[i]]+dis[qv[i]]) {
    			Max=dis[qu[i]]+dis[qv[i]];
    			sta[top=1]=i;
    		} else if(Max==dis[qu[i]]+dis[qv[i]]) {
    			sta[++top]=i;
    		}
    	}
    	for(int i=1; i<=top; ++i) {
    		if(bel[qu[sta[i]]]!=bel[qv[sta[i]]]) return Max;
    		if(bel[qu[sta[i]]]!=bel[qu[sta[1]]]) return Max;
    	}
    	rt=0;
    	sum=siz[bel[qu[sta[1]]]];
    	getRoot(bel[qu[sta[1]]],x);
    	return min(Max,solveAt(rt));
    }
    
    int main() {
    	read(n),read(m);
    	for(int x,y,w,i=n; --i; ) {
    		read(x),read(y),read(w);
    		addEdge(x,y,w);
    		addEdge(y,x,w);
    	}
    	for(int i=1; i<=m; ++i) {
    		read(qu[i]),read(qv[i]);
    	}
    	sum=n; //写成sum=0疯狂T
    	fiz[0]=2e9;
    	getRoot(1,0);
    	printf("%d
    ",solveAt(rt));
    	return 0;
    }
    
  • 相关阅读:
    无线电,电磁波
    ThinkPHP实现支付宝接口功能
    php中发送email
    编程基本功训练:流程图画法及练习
    PHP中的特殊类,接口类和抽象类(都不能直接实例化)
    PHP中面相对象对象的知识点整理
    memcache 与 mencached扩展的区别
    MVC框架 与Smarty
    浏览器缓存机制
    PHP中九大缓存技术总结
  • 原文地址:https://www.cnblogs.com/nosta/p/10230090.html
Copyright © 2011-2022 走看看