动态规划专项intermediate:LA 4015

被自己蠢哭了……已经想到是dfs里分组背包,可就是不知道怎么写,看题解才知道怎么做,然后细节和边界条件又想了半天才弄明白。

其实就是用dp[i][V][0]表示以i为根结点遍历V个点并回到i所需的最小能量,dp[i][V][1]表示以i为根节点遍历V个点(不需回到i)所需的最小能量。

然后就是分组背包了,然后还得注意边界条件,因为V个点作为物品必须全部取完,所以边界为dp[root][1][0]=dp[root][1][1]=0,否则赋为inf。

具体的状态方程就看代码吧。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int inf=1<<30;
int n,e,q,s;
int head[510],pnt[510],nxt[510],cost[510],in[510];
void addedge(int u,int v,int c)
{
    pnt[e]=v;cost[e]=c;nxt[e]=head[u];head[u]=e++;
}
int dp[510][510][2];
int cnt[510];
void dfs(int u)
{
    dp[u][1][0]=dp[u][1][1]=0;
    cnt[u]=1;
    for(int i=head[u];i!=-1;i=nxt[i])
    {
        int v=pnt[i];
        dfs(v);
        cnt[u]+=cnt[v];
        for(int V=cnt[u];V>1;V--)
        {
            for(int j=1;j<=V&&j<=cnt[v];j++)
            {
                dp[u][V][0]=min(dp[u][V][0],dp[u][V-j][0]+dp[v][j][0]+cost[i]*2);
                dp[u][V][1]=min(dp[u][V][1],dp[u][V-j][0]+dp[v][j][1]+cost[i]*1);
                dp[u][V][1]=min(dp[u][V][1],dp[u][V-j][1]+dp[v][j][0]+cost[i]*2);
            }
        }
    }
}
int main()
{
    freopen("in.txt","r",stdin);
    int kase=1;
    while(cin>>n&&n)
    {
        for(int i=0;i<=n;i++)
           for(int j=0;j<=n;j++)
              dp[i][j][0]=dp[i][j][1]=inf;
        memset(head,-1,sizeof(head));
        memset(in,0,sizeof(in));
        e=0;
        for(int i=0;i<n-1;i++)
        {
            int u,v,c;
            cin>>u>>v>>c;
            addedge(v,u,c);
            in[u]++;
        }
        for(int i=0;i<n;i++) if(!in[i]) s=i;
        dfs(s);
        cout<<"Case "<<kase++<<":"<<endl;
        cin>>q;
        while(q--)
        {
            int x;
            cin>>x;
            int ans;
            for(int i=1;i<=n;i++)
            {
                if(x>=dp[s][i][0]||x>=dp[s][i][1])
                    ans=i;
                else break;
            }
            cout<<ans<<endl;
        }
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值