深搜加剪枝,剪枝根据两次异或以后值为本身来写
#include<iostream>
#include<stdio.h>
using namespace std;
#define sc scanf
#define co cout
#define e endl
int maxx,n,m,t,floor;
int b[30],c[30],d[30];
void update(int a[30]){
int tmp = 0;
for(int i=1;i<=n;i++){
tmp += a[i] * c[i];
}
//co<<tmp<<e;
if(tmp>maxx) maxx = tmp;
}
void def(int count,int a[30],int aa[30],int flag){//flag代表进入当前节点前进行的操作 ,count第几次操作,a代表当前要传入的a数组的值,aa代表a上一步的操作的a的值
// 实际上aa数组只有操作1会用到,操作2的aa可以随便填 当传入的flag==1,下一次就没必要使用def(count+1,a,aa,1) 而是将这步操作省略,就是直接剪掉
// 操作0就是从根节点进入的时候还有连续两次操作1清空操作的时候使用
//在奇数层结束,更新奇数层的所有最大值,在偶数层结束,更新所有偶数层的最大值
//更新不能在开头更新
if(count==m){//叶节点必须更新,根节点进入且偶数次操作更新
update(a);
return ;
}
if(count%2==floor||(count==0&&floor==0)){
//co<<"test"<<e;
update(a);
}
if(flag==0){//更新操作1和操作2需要的a数组值
int a1[30],a2[30];
for(int i=1;i<=n;i++){//不论是根节点进入,还是连续两次1操作进入,都套用aa数组,根节点进入aa数组就是一开始的数组a
a1[i] = aa[i] ^ b[i];
a2[i] = aa[d[i]] + t;
}
def(count+1,a1,aa,1);
def(count+1,a2,aa,2);
}else if(flag==1){//之前进行1操作
int a2[30];
for(int i=1;i<=n;i++){
a2[i] = a[d[i]] + t;
}
//def(count+1,a1,aa,1);1操作替换掉
//def(count+1,a,aa,0); 可以剪枝
def(count+1,a2,aa,2);
}else if(flag==2){//之前进行2操作,其他操作按计划进行
int a1[30],a2[30];
for(int i=1;i<=n;i++){
a1[i] = a[i] ^ b[i];
a2[i] = a[d[i]] + t;
}
def(count+1,a1,aa,1);
def(count+1,a2,aa,2);
}
return ;
}
int main(){
int a[30];
while(sc("%d %d %d",&n,&m,&t)!=EOF){//每次输入,重置奇数偶数层m判断,重置最大值
maxx = -100000000;//必须为该值,极端情况一个数操作一次,a是10000,c是-10000
floor = m%2;
for(int j=1;j<=n;j++){
sc("%d",&a[j]);
}
for(int j=1;j<=n;j++){
sc("%d",&b[j]);
}
for(int j=1;j<=n;j++){
sc("%d",&c[j]);
}
for(int j=1;j<=n;j++){
sc("%d",&d[j]);
}
def(0,a,a,0);
co<<maxx<<e;
}
return 0;
}