整个流程:
- 初始一个状态
- 通过设计的转移方式进行转移,并求出所有转移方式对应的增量和新状态
- 依次从最好的状态进行判断是否满足解除禁忌(也就是能不能选为新状态)
- 可以选为新状态的条件:(1).价值大于历史最优值。(2).禁忌表中没有
- 如果不满足上述两条,选择次优状态再进行判断。
- 重复上述过程
注:有的禁忌表存的禁忌状态是操作,我这里存的就是历史选择状态。
禁忌表长度影响收敛,太小的话收敛不到最好值。
#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;
}