1.24测试题summary
1.子集和问题
这个题有多个解,但题面没有明确说出需要哪组解。
此题最大不同是搜索的终止条件可以变化
注意优化,把不需要搜索的数据判断出来,直接给出No Solution的答案!
#include#define enter printf("\n") using namespace std; int s[10000],a[10000],sum[10000]; //原集合,子集合 int n,c; void print(int l){ for(int i = 1;i < l;i++){ printf("%d ",a[i]); } enter; exit(0); } void dfs(int x,int k,int tot){ //子集中元素个数,当前取第几个元素,当前元素和 if(tot == c) { print(k); } if(tot > c) return; if(tot+sum[x] return; for(int i = x;i <= n;i++){ //不能重复取 a[k] = s[i]; // save dfs(i+1,k+1,tot+s[i]); } } int main(){ cin>>n>>c; for(int i = 1;i <= n;i++){ scanf("%d",&s[i]); } for(int i = n;i > 0;i--){ sum[i]=sum[i+1]+s[i]; } if(sum[1]>=c) dfs(1,1,0); printf("No Solution!"); return 0; }
2.分配工作
n个人选n项工作的一种,各不相同,求最小费用
从题意就能推出要用深度搜索的,核心代码没问题,但是超时只得80分,后面调了很久,代码各种优化
其实关键部分还是总费用比当前最小费用大就结束,不需要往下推,因为求的是最小
#includeusing namespace std; bool b[21]; //第i项工作是否分配?1:0 int t[21][21]; void search(int n,int k,int w){ //第k个人要分配工作 ,总费用 if(k > n){ if(w < t[0][0]){ t[0][0] = w; } return; } if(w > t[0][0]) return; for(int j = 1;j <= n;j++){ if(!b[j]){ b[j] = 1; search(n,k+1,w+t[k][j]); b[j] = 0; } } } int main(){ int n; t[0][0] = 10000; cin>>n; for(int i = 1;i <= n;i++){ //i行表示第i个人 for(int j = 1;j <= n;j++){ //j列表示第j项工作费用 scanf("%d",&t[i][j]); } } search(n,1,0); printf("%d",t[0][0]); return 0; } /* 3 4 2 5 2 3 6 3 4 5 4.339s--1.102s */
3.load负载问题
求最靠近载重量的组合,这个和拔河问题异曲同工,不过不知道是不是搜索的算法用时过长,最后还是没ac,以下是搜索算法。
(可能条件判断还能再优化一下)
#includeusing namespace std; int w[200],maxk = 0; bool b[200]; void search(int n,int c,int k,int z,int q){ //n,c,货物数,总重 ,前一个货物 for(int i = q+1;i <= n;i++){ if(b[i]) continue; if(z+w[i]>c){ if(z > maxk) maxk = z; continue; } b[i] = 1; search(n,c,k+1,z+w[i],i); b[i] = 0; } } int main(){ int n,c,sum=0; scanf("%d %d",&n,&c); for(int i = 1; i <= n;i++){ scanf("%d",&w[i]); sum+=w[i]; } if(sum<c){ printf("%d",sum); return 0; } search(n,c,1,0,0); printf("%d",maxk); return 0; }
就在刚才!终于调过了!!
代码如下
之前的错误是用b[i]和q双重方式来解决互斥的问题,自己还没注意到,现在做了关键性的精简,甚至循环里只有一句,整个搜索精简到四行!
#includeusing namespace std; int w[200],maxk = 0; int n,c; void search(int z,int q){ //货物数,总重 ,前一个货物 if(z>c) return; if(z>maxk) maxk=z; for(int i = q+1;i <= n;i++){ search(z+w[i],i); } } int main(){ int sum=0; scanf("%d %d",&n,&c); for(int i = 1; i <= n;i++){ scanf("%d",&w[i]); sum+=w[i]; } if(sum<c){ printf("%d",sum); return 0; } search(0,0); printf("%d",maxk); return 0; }
4.字符序列
给定字符序列长,在{A,B,C}元素中选择元素来构成,要求相邻的两个2字符子序列不能相同。这题一开始理解错了按照不必相邻的情况写的,后面改过来,做得还算顺利
#includeusing namespace std; int n,ans; int a[14]; bool mycmp(){ for(int i = 1;i <=n - 3;i++){ if(a[i]==a[i+2]&&a[i+1]==a[i+3]) return 0; } return 1; } void search(int pos){ if(pos>n){ if(mycmp()){ ans++; } return; } for(int i = 0;i < 3;i++){ a[pos] = i; search(pos+1); a[pos] = 0; } } int main(){ cin>>n; search(1); printf("%d",ans); return 0; }