APIO2010:巡邏 樹中最長K條鏈

。。。

無語BZOJ掛了,CF也掛了。Bless All..

題目鏈接: (木有) APIO2010

題目描述:求一顆樹裏的邊不相交的K條鏈,使得K條鏈經過的邊數之和最大。( 本題K<=2)

首先:

http://blog.sina.com.cn/s/blog_61034ad90100ii8r.html

http://www.cnblogs.com/procedure2012/archive/2012/03/11/2390792.html


K=1,.....直接求最長鏈。BFS兩次找直徑或者樹形DP。

K=2,有貪心的方法:先求最長鏈,再把經過的邊權設爲-1,再求最長鏈,這下要兩次樹形DP。(k=2正確,k>2不知道正確性)

K>2 ,樹形DP可做


令F[i][j][k]表示當前在i節點的子樹中找到了j條完整的鏈,且當前的狀態是k。

k=0,表示沒有能和i的父親一起合成一條長鏈的一半的鏈。

k=1,表示有且只有一條到j的半條鏈,可以向上繼續延伸。(最多一條,大於一條的話在就要在i到fa[i]的路上相交了)


一個兒子的所有更新不能重疊,不能直接動態用f數組來更新f數組所以要新建一個tmp數組保存上一次狀態。

下面的更新都相當於做了一個揹包。x表示i的兒子。


上面第一個表示從兒子中選一些現成的鏈來組合。 第二個表示x裏的半條鏈和i的半條鏈和鏈接x,i的邊組合成一條新鏈。x中已經有t條完整鏈了,所以是[i-t+1][1]


第一個表示從兒子x中選t個完整的鏈和之前的j-t個完整的鏈並且一條半條鏈合成。第二個表示i中本來的t個完整的鏈和x中i-t個完整的鏈和一條半條鏈與i,x的路徑合成而成i的半條鏈。

還有K條最長鏈答案是:


(這道題的答案不是這個啊。)


DP代碼(基本抄襲):

#include <cstdio>
#include <cstring>
#include <algorithm>
#define rep(i,l,r) for (int i=l;i<=r;++i)
#define per(i,r,l) for (int i=r;i>=l;--i)
int getx(){
	char c;int x;bool pd=false;
	for (c=getchar();c!='-'&&(c<'0'||c>'9');c=getchar());
	if (c=='-') c=getchar(),pd=true;
	for (x=0;c>='0'&&c<='9';c=getchar())
		x=(x<<3)+(x<<1)+c-'0';
	return pd?-x:x;
}
bool upmax(int &a,const int &b){return a<b?a=b,1:0;}
const int MAX_N=100005,MAX_K=2+1;
int N,K;
int first[MAX_N],next[MAX_N<<1],to[MAX_N<<1];
int tal=1;
void tjb(int x,int y){
	next[++tal]=first[x];
	first[x]=tal;
	to[tal]=y;
}
int f[MAX_N][MAX_K][2];
int tmp[MAX_K][2];
void dfs(int v,int fa){
	for (int k=first[v];k;k=next[k]){
		int u=to[k];
		if (u==fa) continue;
		dfs(u,v);
		memcpy(tmp,f[v],sizeof f[v]);
		per(j,K,0) per(t,j,0){
			upmax(f[v][j][0],f[u][t][0]+tmp[j-t][0]);
			if (j-t-1>=0) upmax(f[v][j][0],f[u][t][1]+tmp[j-t-1][1]+1);
			upmax(f[v][j][1],f[u][t][0]+tmp[j-t][1]);
			upmax(f[v][j][1],f[u][t][1]+tmp[j-t][0]+1);
			}
		}
}
int main(){
	freopen("patrol.in","r",stdin);
	freopen("patrol.out","w",stdout);
	N=getx(),K=getx();
	rep(i,1,N-1){
		int x=getx(),y=getx();
		tjb(x,y);tjb(y,x);
		}
	dfs(1,0);
	printf("%d\n",2*(N-1)+K-std::max(f[1][K][0],f[1][K-1][1]));
}



這份代碼是傻逼的貪心K≤2,寫的相當的醜。醜到基本不能看。

#include <cstdio>
#include <algorithm>
#define rep(i,l,r) for (int i=l;i<=r;++i)
int getx(){
	char c;int x;bool pd=false;
	for (c=getchar();c!='-'&&(c<'0'||c>'9');c=getchar());
	if (c=='-') c=getchar(),pd=true;
	for (x=0;c>='0'&&c<='9';c=getchar())
		x=(x<<3)+(x<<1)+c-'0';
	return pd?-x:x;
}
bool upmax(int &a,const int &b){return a<b?a=b,1:0;}
const int MAX_N=100005;
int n,k;
int first[MAX_N],next[MAX_N<<1],to[MAX_N<<1];
int tal=1;
void tjb(int x,int y){
	next[++tal]=first[x];
	first[x]=tal;
	to[tal]=y;
}
const int INF=~0U>>2;
int mxlen=-INF;
struct Node{
	int l,v;
	Node(int _l=0,int _v=0):l(_l),v(_v){}
};
int a,b;
int fa[MAX_N],dep[MAX_N];
int c[MAX_N];
Node dfs(int v,int fax,int dp){
	fa[v]=fax;dep[v]=dp;
	Node mx1(0,v),mx2(-INF,v),tp;
	bool pd=true;
	for (int k=first[v];k;k=next[k]){
		int u=to[k];
		if (u==fax) continue;
		pd=false;
		tp=dfs(u,v,dp+1);
		if (tp.l>mx1.l) mx2=mx1,mx1=tp;
		else if (tp.l>mx2.l) mx2=tp;
		}
	if (upmax(mxlen,mx1.l+mx2.l))
		a=mx1.v,b=mx2.v;
	if (pd) return Node(c[v],v);
	return Node(mx1.l+c[v],mx1.v);
}
void sol(){
	if (dep[a]<dep[b]) std::swap(a,b);
	while (dep[a]!=dep[b])
		c[a]=-1,a=fa[a];
	while (a!=b){
		c[a]=c[b]=-1;
		a=fa[a],b=fa[b];
		}
}
void work(){
	rep(i,2,n) c[i]=1;c[1]=0;
	dfs(1,0,1);
	int mx=mxlen;
	if (k==1){printf("%d\n",(n-1+k)*2-(mx+k));exit(0);}
	sol();
	mxlen=-INF;
	dfs(1,0,1);
	if (mxlen<0) printf("%d\n",(n-1+k)*2-(mx+k));
	else printf("%d\n",(n-1+k)*2-(mxlen+mx+k));
}
int main(){
	freopen("patrol.in","r",stdin);
	freopen("patrol.out","w",stdout);
	n=getx(),k=getx();
	rep(i,1,n-1){
		int x=getx(),y=getx();
		tjb(x,y);tjb(y,x);
		}
	work();
}


發佈了41 篇原創文章 · 獲贊 1 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章