【题目地址】http://www.apio.olympiad.org/
【算法分析】
就是求两(一)条不相交的最长链。
F[i][j][k]表示i这个结点,已完成的链有j条,k表示有无一条只有一边的可延伸链,所得到的最大长度。
然后就像背包一样转移。
【CODE】
#include
struct edge{int x,y;edge *next;}sp[N*2],*ls[N];
int n,L,e,tot;
int F[N][3][2],pF[3][2];
inline void addedge(int x,int y){
sp[++e].x=x; sp[e].y=y; sp[e].next=ls[x]; ls[x]=&sp[e];
}
void init(){
e=0;
memset(ls,0,sizeof(ls));
int i,x,y;
scanf("%d%d",&n,&L);
for (i=1;i
addedge(x,y);
addedge(y,x);
}
}
inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return x
if (t->y!=fa) dp(t->y,t->x);
F[p][0][0]=0;
F[p][0][1]=0;
int j,k,pj,pk;
tot=0;
for (edge *t=ls[p];t;t=t->next) if (t->y!=fa){
memcpy(pF,F[p],sizeof(pF));
for (j=0;j<=L;j++)
for (pj=0;pj+j<=L;pj++){
F[p][pj+j][0]=max(F[p][pj+j][0],pF[pj][0]+F[t->y][j][0]);
F[p][pj+j][1]=max(F[p][pj+j][1],pF[pj][0]+F[t->y][j][1]+1);
F[p][pj+j][1]=max(F[p][pj+j][1],pF[pj][1]+F[t->y][j][0]);
if (pj+j+1<=L)
F[p][pj+j+1][0]=max(F[p][pj+j+1][0],pF[pj][1]+F[t->y][j][1]+1);
}
}
}
void solve(){
int ans=0;
memset(F,200,sizeof(F));
dp(1,0);
ans=max(ans,F[1][1][0]);
ans=max(ans,F[1][0][1]);
if (L==2){
ans=max(ans,F[1][1][1]);
ans=max(ans,F[1][2][0]);
}
printf("%dn",2*n-2-ans+L);
}
int main(){
freopen("patrol.in","r",stdin);
freopen("patrol.out","w",stdout);
init();
solve();
return 0;
}
大牛你们这都是从哪得知的比赛啊
回复darkgtbd:= =我是去现场参加了这个比赛。。。。,不过很不幸地酱油了。。。
其实有贪心算法。。。证明也不是很复杂。。。比树形DP思路清晰很多。不过代码量会稍多点(也可能是我写猥琐了)
回复RP小魚兒:当时有一个人说了一种贪心,就是先找一条最大权链,然后把链上边权置为-1,然后再找一条最大权链。可能是这种?MS和最大流的修正差不多。。。
回复edward_mj: 刚写了题解….和那个一样。不过证明不知道对不对,神牛有空就去看看吧
什么是 “k表示有无一条只有一边的可延伸链”
回复哈凌大侠:你想想背包问题吧。现在假设下面有x条链伸上来。如果x是奇数,那么这个k=1。表示可以向父亲连。如果x是偶数,那么这个k=0。这样他们下面就已经一一配对好。练成链弄到一起了。不知道这样你懂了吗?
有两句不太理解 F[p][pj+j+1][0]=max(F[p][pj+j+1][0],pF[pj][1]+F[t->y][j][1]+1);本来不可以和父亲连,却转移出来了pF[pj][1],为什么呢 ans=max(ans,F[1][1][1]);1节点不是没有父亲吗?怎么和父亲连呢?麻烦请大牛解释一下
回复哈凌大侠:我的一个状态本质上是:已经配对好了j“对”链。然后第3维表示的是,现在是否有未配对的单链延伸到本点。
嗯,我想了半天终于想通了。这个问题攒好长时间了,谢谢耐心讲解!