。。。
無語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();
}