您的位置:首页 > 其它

hdu 4876 ZCC loves cards(暴力+剪枝)

2014-07-27 09:55 393 查看
因为从n张里选k张需要C(n,k),然后k张全排列需要k!。这样果断会超时,所以需要剪枝。当选出k张后先不排序,判断每张牌选或不选共2^k种可能的组合能不能使结果更优。如果不能,就没必要在进行排列组合了。

#include<algorithm>
#include<stdio.h>
#include<cstring>
using namespace std;
int a[25],vis[205],save[25],have[25],ans[205];
int n,k,l,r;

//每张牌选或不选,共2^k种可能
void ok_calc(int no,int sum)
{
vis[sum] = 1;
if(no == k) return;
ok_calc(no+1,sum^save[no]);
ok_calc(no+1,sum);
}

//计算不连续选的话最优解
bool max_cur()
{
memset(vis,0,sizeof vis);
ok_calc(0,0);
for(int i = l;i <= r;i++)
if(!vis[i]) return false;
return true;
}

void calc()
{
if(!max_cur()) {return;}
for(int i = 0;i < k;i++) have[i] = save[i]; //have用来进行全排列
do{
memset(ans,0,sizeof ans);
for(int i = 1;i <= k;i++) //选几张
{
for(int j = 0;j < k;j++) //从第几张开始选
{
int tmp = 0;
for(int kk = j;kk < j+i;kk++)
tmp = tmp^have[kk%k];
ans[tmp] = 1;
}
}
for(int i = l;;i++)
{
if(!ans[i]){r = max(i-1,r);break;}
}
}while(next_permutation(have+1,have+k));
//一定要从have+1开始求下一个全排列,不然会超时
//因为是环,所以可以得到全部结果
}

//no:当前搜到第几张牌,num:一共已经选择了几张牌
void dfs(int no,int num)
{
if(num == k) {calc();return;}
else
{
for(int i = no;i < n;i++)
{
//保存当前选的牌
save[num] = a[i];
dfs(i+1,num+1);
}
}
}

int main()
{
while(scanf("%d %d %d",&n,&k,&l)!=EOF)
{
for(int i = 0;i < n;i++) scanf("%d",&a[i]);
sort(a,a+n);
//初始化右端点值
r = l - 1;
dfs(0,0);
if(r < l) printf("0\n");
else printf("%d\n",r);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: