禁忌搜索算法之01背包问题(C语言实现)

整个流程:

  1. 初始一个状态
  2. 通过设计的转移方式进行转移,并求出所有转移方式对应的增量和新状态
  3. 依次从最好的状态进行判断是否满足解除禁忌(也就是能不能选为新状态)
  4. 可以选为新状态的条件:(1).价值大于历史最优值。(2).禁忌表中没有
  5. 如果不满足上述两条,选择次优状态再进行判断。
  6. 重复上述过程
    注:有的禁忌表存的禁忌状态是操作,我这里存的就是历史选择状态。
    禁忌表长度影响收敛,太小的话收敛不到最好值。
#include<bits/stdc++.h>
using namespace std;
#define maxn 105
#define maxm 1006
#define ll long long int
#define INF 0x3f3f3f3f
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
#define mem(a) memset(a,0,sizeof(a))
#define sqr(x) (x*x)
#define inf (ll)2e18+1
#define PI acos(-1)
#define mod 10007
#define db double
#define auto(i,x) for(int i=head[x];i;i=ed[i].nxt)
///实现上使用状压n个物品的选择状态 所以 n 不能太大
///不然对时间空间复杂度要求太高
///禁忌表长度太短不容易收敛
ll read(){
    ll x=0,f=1ll;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
     while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
     return f*x;
}
int n,m,W;
db xiaorand(db low,db up,db jin){
    db down=min(0.0,low);
    low-=down,up-=down;
    int l=(int)low*jin,r=(int)up*jin;
    int len=r-l+1;
    int num=rand()%len + l;
    return 1.0*num/jin + down;
}
struct node{int w,v;}a[maxn];
queue<ll>q;
int jj_len=15;
unordered_map<ll,int>mp;
int f(ll x){
    ll sumv=0,sumw=0;
    inc(i,1,n)if(x&(1<<(i-1))){sumv+=a[i].v,sumw+=a[i].w;}
    return sumw <= W ? sumv : -INF;
}
struct state{
    int val;ll s;
    bool operator < (const state &rid)const{
        return val < rid.val;
    }
};
priority_queue<state>biao;
void solve(int step){
    ll sta=0;int kase=0;
    inc(i,0,n-1)if(rand()%2==1)sta+=(1<<i);
    int c1=f(sta),c_max=c1;
    mp[sta]=1;q.push(sta);
    while(step--){
        printf("%d : %d\n",++kase,c_max);
        while(!biao.empty())biao.pop();
        inc(i,0,n-1){
            ll now=sta^(1<<i);int val=f(now);
            biao.push((state){val,now});
        }
        while(!biao.empty()){
            ll nowsta=biao.top().s;int cur_ma=biao.top().val;biao.pop();
            if(mp[nowsta]==0){
                if(q.size()>=jj_len){mp[q.front()]=0;q.pop();}
                q.push(nowsta);mp[nowsta]=1;
                sta=nowsta;
                c_max=max(c_max,cur_ma);
                break;
            }
            else if(c_max<cur_ma){
                c_max=cur_ma;
                if(q.size()>=jj_len){mp[q.front()]=0;q.pop();}
                q.push(nowsta);mp[nowsta]=1;
                sta=nowsta;
                break;
            }
            else continue;
        }
    }
}
int main()
{
    srand(time(NULL));
    n=read();m=read();W=read();
    inc(i,1,n)a[i].w=read(),a[i].v=read();
    solve(1000);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值