hdu 4876 暴力剪枝

hdu 4876 终于过了, 之前写的代码虽然思路是这样的但是有好多可以优化的地方没有注意所以一直超时超时超时!,学习了一下别人的代码,虽然看上去没什么差别但实际上却可以节省很多时间,恩恩又学到了一些技巧~     ^_^ 。

【题意】:给定一些卡片,每个卡片上有数字,现在选k个卡片,绕成一个环,每次可以再这个环上连续选1 - k张卡片,得到他们的异或和的数,给定一个L,问能组成[L,R]所有数字的情况下,R的最大值是多少.

【思路】:暴力+剪枝  枚举在m个数里选k个数的 C(m,k)种情况,但是要先判断一下,再判断一下要不要把这个组合再排成A(k,k)种序列,这个判断就可以剪枝,要是这这个组合可以得到的所有异或值里的最大都不比上一次得到的R值大。就

写的第一个超时代码

  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <string.h>
  4 #include <algorithm>
  5 using namespace std;
  6 int k,L,R,n,m,t;
  7 bool vis[22],vis1[22];
  8 int a[22],temp[22];
  9 int xorr[100],huan[102];
 10
 11 void dfs1(int step)
 12 {
 13     if(step==k)//d得到这个顺序的所有异或值
 14     {
 15         int num=0;
 16
 17         for(int j=0; j<k; j++)
 18         {
 19             int tempxor=0;
 20             for(int p=0; p<k; p++)
 21             {
 22                 tempxor^=huan[(j+p)%k];
 23                 xorr[num++]=tempxor;
 24             }
 25         }
 26         sort(xorr,xorr+num);
 27         int *wei;
 28         int tempR=0;
 29         wei=unique(xorr,xorr+num);
 30
 31         bool flag=false;
 32         for(int *j=xorr; j<=wei; j++)
 33         {
 34             if(flag)
 35             {
 36                 if((*j-1)==tempR)
 37                     tempR++;
 38                 else break;   //中间跳了一个
 39             }
 40             if((*j)==L)
 41             {
 42                 flag=true;
 43                 tempR=L;
 44             }
 45         }
 46         if(tempR>R)
 47             R=tempR;
 48         return ;
 49     }
 50     for(int i=0; i<k; i++)
 51     {
 52         if(!vis1[i])
 53         {
 54
 55             huan[step]=temp[i];
 56             vis1[i]=true;
 57             dfs1(step+1);
 58             vis1[i]=false;
 59         }
 60     }
 61 }
 62
 63 void zhankai()
 64 {
 65     memset(vis1,false,sizeof(vis1));
 66     dfs1(0);
 67 }
 68
 69 void dfs(int x,int p)
 70 {
 71     if(x==k)
 72     {
 73         int maxx=0;
 74         for( int p=0; p<(1<<k); p++)
 75         {
 76             int yihuo=0;//得到每个子集的亦或值
 77             for(int q=0; q<k; q++)
 78                 if((1<<q)&p)
 79                     yihuo^=temp[q];
 80             if(maxx<yihuo)
 81                 maxx=yihuo;
 82         }
 83         if(maxx>R)
 84             zhankai();
 85     }
 86     for(int i=p; i<n; i++)
 87         if(!vis[i])
 88         {
 89             temp[x]=a[i];
 90             vis[i]=true;
 91             dfs(x+1,i+1);
 92             vis[i]=false;
 93         }
 94 }
 95
 96 int main()
 97 {
 98     while(~scanf("%d%d%d",&n,&k,&L))
 99     {
100         for(int i=0; i<n; i++)
101             scanf("%d",&a[i]);
102         memset(vis,false,sizeof(vis));
103         R=-1;
104         dfs(0,0);
105         if(L>R)
106             printf("0\n");
107         else
108         printf("%d\n",R);
109     }
110     return 0;
111 }

修改后的:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <algorithm>
 5 using namespace std;
 6 int k,L,R,n,m,t;
 7 bool vis4[202],v[1002];
 8 int a[22],temp[22];
 9 int huan[102],kl[7];
10 bool xorr[100002];
11
12 void dfs1(int num,int sum)      //!!!
13 {
14     vis4[sum]=true;
15     if(num==k)
16         return ;
17     dfs1(num+1,sum^temp[num]);    //每个点都可以选择加入异或  或者不异或 共2^k种
18     dfs1(num+1,sum);
19 }
20
21
22 void zhankai()
23 {
24     int have[202];
25     for (int i = 0; i < k; i++)
26         have[i] = temp[i];
27     do
28     {
29         memset(v, 0, sizeof(v));
30         for (int i = 0; i < k; i++)
31         {
32             int ans = 0;
33             for (int j = i; j < k + i; j++)//!!!! 这里j没必要从0开始
34             {
35                 ans ^= have[(j % k)];
36                 v[ans] = 1;
37             }
38         }
39         for (int i = L; i <= L + k * k; i++)
40             if (!v[i])
41             {
42                 R = max(R, i - 1);
43                 break;
44             }
45     }
46     while(next_permutation(have + 1, have + k));   //!!直接调函数枚举每个序列
47 }
48
49 void dfs(int x,int p)
50 {
51     if(x==k)
52     {
53         memset(vis4,false,sizeof(vis4));
54         dfs1(0,0);      // 之前我的方法 用的时间是(2^k)*k  这个只要2^k,而且代码还特简洁;
55         for(int i=L; i<=R; i++)
56             if(!vis4[i])
57                 return ;      //!! 这里不是找最大值而是找是否可以连续覆盖,写起来有简单点
58         zhankai();
59     }
60     for(int i=p; i<n; i++)
61     {
62         temp[x]=a[i];
63         dfs(x+1,i+1);
64     }
65 }
66
67 int main()
68 {
69     while(~scanf("%d%d%d",&n,&k,&L))
70     {
71         for(int i=0; i<n; i++)
72             scanf("%d",&a[i]);
73         sort(a,a+n);//!!!!!拍完学后  dfs得到的是这个组合的最小序,枚举该组合的所有序列可以方便的使用 next_permutation
74
75         R=-1;
76         dfs(0,0);
77         if(R<L)
78             printf("0\n");
79         else
80             printf("%d\n",R);
81     }
82     return 0;
83 }

hdu 4876 暴力剪枝

时间: 2024-10-10 17:49:05

hdu 4876 暴力剪枝的相关文章

hdu 4876(剪枝+暴力)

题意:给定n,k,l,接下来给出n个数,让你从n个数中选取k个数围成一圈,然后从这k个数中随意选出连续的m(m>=1&&m<=k)个数进行异或后得到[l,r]区间的所有值,让你求最大的r. 分析:关键问题是需要剪枝! 代码实现: #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #inclu

HDU 4876 ZCC loves cards(暴力剪枝)

HDU 4876 ZCC loves cards 题目链接 题意:给定一些卡片,每个卡片上有数字,现在选k个卡片,绕成一个环,每次可以再这个环上连续选1 - k张卡片,得到他们的异或和的数,给定一个L,问能组成[L,R]所有数字的情况下,R的最大值是多少 思路:暴力C(20, 6),然后对于每个序列去全排后模拟计算值, 不过之前要有个剪枝,全排前,先把k个数随机取数(即不用连续),然后如果这样还满足不了,那么连续的情况肯定也满足不了,直接结束,不进入全排.这样一来由于满足不了的情况实际上是占绝大

hdu 4876 ZCC loves cards(暴力)

题目链接:hdu 4876 ZCC loves cards 题目大意:给出n,k,l,表示有n张牌,每张牌有值.选取其中k张排列成圈,然后在该圈上进行游戏,每次选取m(1≤m≤k)张连续的牌,取牌上值的亦或和.要求找到一个圈,使得L~R之间的数都可以得到,输出R.如果R < L输出0. 解题思路:暴力,首先预处理出来每种选取的亦或值,然后在该基础上从可以组成L的状态中挑选一个,L+1的状态中挑取一个,知道说总的挑取出所有状态中选中的牌的个数大于K为值,然后用全排序去查找最大的R. #includ

HDU 4876 ZCC loves cards

我决定记录下这么恶心的代码.比赛的时候头晕脑胀,写得好搓,错的地方好多好多,回来调了好久.... 做法大概就是C(20,6)选出卡牌后,再k!枚举排列,再k*k得出该排列能得出什么数字. 当然,光这样做绝对会T,里面加了各种剪枝后就1650ms险过了.. 最主要的剪枝是选出k张牌后,看牌能不能组成L~ans里面各个数字,能才进行下一步.然后k!可以拆成(k-x)!*(x!)..不过这里其实大概没什么大优化吧 #include<cstdio> #include<iostream> #

hdu 4876

ZCC loves cards Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 828    Accepted Submission(s): 184 Problem Description ZCC loves playing cards. He has n magical cards and each has a number on it

hdu 4109 dfs+剪枝优化

求最久时间即在无环有向图里求最远路径 dfs+剪枝优化 从0节点(自己增加的)出发,0到1~n个节点之间的距离为1,mt[i]表示从0点到第i个节点目前所得的最长路径 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<vector> using namespace std; const

hdu 5887 搜索+剪枝

Herbs Gathering Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 687    Accepted Submission(s): 145 Problem Description Collecting one's own plants for use as herbal medicines is perhaps one of t

HDU 4876 ZCC loves cards _(:зゝ∠)_ 随机输出保平安

GG,,,g艹 #include <cstdio> #include <iostream> #include <algorithm> #include <string.h> #include <vector> #include <queue> #include <math.h> using namespace std; vector<int>G[21][7];//G[i][j] 表示n=i k=j的情况下 二进

uva10245 - The Closest Pair Problem(暴力+剪枝)

题目:uva10245 - The Closest Pair Problem(暴力+剪枝) 题目大意:给出N个点,求这些点中最小的两点距离. 解题思路:把这些点中两两之间的距离都算出来,这样的复杂度是O(n^2),会超时,所以加了一个减枝. 先将所有的点按照x坐标排序.然后在计算的过程中,如果发现要计算的这两点的X坐标之差的绝对值已经大于等于当前的最小值,那么说明后面的点计算距离一定比这个最小值要大. 这题的正解貌似是分治法,可惜没看懂. 代码: #include <stdio.h> #inc