这个题目被想得复杂了
树形dp的思维还是不够
代码中ans[t][i][j]
的意思是节点t走了i步,离节点还有j的距离的最优解
状态转移就是背包的合并
看了别人的结题报告后明白其实第三维可以压缩,ans[t][i][0]表示回到节点 ans[t][i][1]表示不回节点
其实大家应该能明白了上面的状态表示法虽然更容易理解些,但是重复问题较多所以效率低
代码写得很丑,凑合着看吧
#include
#include
#include
using namespace std;
const int maxn=101,inf=9999999;
int a[maxn],text[maxn];
int m,n;
struct
{
int to,next;
}e[maxn*2];
int head[maxn],lon;
int edgeini(int n)
{
for(int i=1;i<=n;i++)
head[i]=-1;
return(0);
}
int edgemake(int from,int to)
{
e[++lon].to=to;
e[lon].next=head[from];
head[from]=lon;
return(0);
}
int son[maxn];
int dfs(int t)
{
text[t]=1;
for(int k=head[t];k!=-1;k=e[k].next)
{
if(text[e[k].to]) continue;
dfs(e[k].to);
son[t]+=son[e[k].to];
}
son[t]++;
return(0);
}
int ans[maxn][2*maxn][maxn];
int dp(int t)
{
// printf("%d\n",t);
text[t]=1;
for(int i=0;i<=(son[t]-1)*2;i++)
for(int j=0;j
ans[t][i][j]=-inf;
ans[t][0][0]=a[t];
for(int k=head[t];k!=-1;k=e[k].next)
{
if(text[e[k].to]==1) continue;
dp(e[k].to);
for(int i=(son[t]-1)*2;i>=0;i--)
for(int j=0;j
if(ans[t][i][j]!=-inf)
for(int p=(son[e[k].to]-1)*2;p>=0;p--)
for(int q=0;q
if(ans[e[k].to][p][q]!=-inf)
{
if(i+j+1+p<=(son[t]-1)*2)
if(ans[t][i+j+1+p][q+1]
ans[t][i+j+1+p][q+1]=ans[t][i][j]+ans[e[k].to][p][q];
if(1+p+q+1+i<=(son[t]-1)*2)
if(ans[t][1+p+q+1+i][j]
ans[t][1+p+q+1+i][j]=ans[t][i][j]+ans[e[k].to][p][q];
}
}
return(0);
// printf("%d\n",t);
}
int main()
{
// freopen("in.txt","r",stdin);
while(scanf("%d %d",&n,&m)!=EOF)
{
lon=0;
memset(son,0,sizeof(son));
edgeini(n);
for(int i=1;i<=n;i++)
scanf("%d ",&a[i]);
for(int i=1;i
{
int from,to;
scanf("%d %d",&from,&to);
edgemake(from,to);
edgemake(to,from);
}
floyed(n);
memset(text,0,sizeof(text));
dfs(1);
memset(text,0,sizeof(text));
dp(1);
int answer=0;
for(int i=0;i<=m;i++)
for(int j=0;j<=n;j++)
if(ans[1][i][j]>answer)
answer=ans[1][i][j];
printf("%d\n",answer);
}
return 0;
}