。。。
无语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();
}