Five in a Row, Again-记录状态的dfs+剪枝

本文探讨了一种使用二进制记录状态的方法,通过优化算法在已知路径中寻找最优解,重点关注路径的长度和成本。利用C++实现,通过实例展示了算法的应用与效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用一个二进制记录当前状态。

二进制中的0代表当前点已经被走过,1代表当前点还未走过。

如果当前二进制之前计算过,且值大于当前值的话,那么就终止不走。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
int shuyu[5001];
int n;
int w[101][101];
int e[101][101];
int s[101];
int dp[5001];
void init()
{
    int ns=1;
    for(int i=1;i<=12;i++)
    {
        shuyu[ns]=i;
        ns=ns*2;
    }
    for(int i=1;i<=5000;i++)if(shuyu[i]==0)shuyu[i]=shuyu[i-1];
}
void dos(int num,int exp,int as)
{
    //cout<<num<<" "<<exp<<" "<<as<<endl;
    if(num<dp[as])return ;
    dp[as]=num;
    if(as==0)return;
    int st;
    st=as;
    int ed;
    ed=as;
    while(ed)
    {
        st=ed&(ed-1);
        st=ed-st;
        int pp=shuyu[st];
        if(exp>s[pp])dos(num+w[1][pp],exp+e[1][pp],as-(1<<(pp-1)));
        else dos(num,exp+e[1][pp],as-(1<<(pp-1)));
        ed=ed-st;
    }
}
int main()
{
    int _,i,j;
    init();
    scanf("%d",&_);
    while(_--)
    {
        memset(dp,0,sizeof(dp));
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                scanf("%d",&e[i][j]);
            }
        }
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                scanf("%d",&w[i][j]);
            }
        }
        for(i=1;i<=n;i++)
        {
            scanf("%d",&s[i]);
        }
        int as=0;
        int ns=1;
        for(i=1;i<=n;i++)
        {
            as+=(1<<(i-1));
        }
        as-=1;
        int leap=1;
        int ans=0;
        while(leap)
        {
            leap=0;
            for(i=2;i<=n;i++)
            {
                if(s[1]<=s[i])continue;
                if((1<<(i-1))&as)
                {
                    s[1]+=e[1][i];
                    as-=(1<<(i-1));
                    ans+=w[1][i];
                    leap=1;
                }
            }
        }
        if(as==0)cout<<ans<<endl;
        else
        {
            dp[as]=ans;
            dos(ans,s[1],as);
            cout<<dp[0]<<endl;
        }
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值