花了一个多小时的时间搞定了这道题= =
给出题面:
很明显这道题是一道搜索的题,我用的是dfs+回溯。暴力的方法是设置一个计数器,如果满足条件时就进入下一重dfs,每次都判断是否达到要求,如果所用的肥料数最小的话就更新数组,这样的话可以拿下80%的数据,但仔细算算,如果是极限数据的话,需要进行15重dfs,每重都有一个二重循环,这样的话时间复杂度大概是(15*15)^15,很明显这样会超时,这时候需要做优化。
仔细想想,每重dfs都是从数组的起点开始搜索,但实际上搜索的时候做了许多次重复,所以用了大部分的时间做了重复的操作,那具体应该怎么办呢?很显然,因为每次都是从数组起点开始搜索,所以上一重dfs中所搜索到的数的之前的数都是做的重复操作,那么可以建立一个指针,指针指向上一重dfs中搜索到的位置,在本次搜索中从指针的下一位开始搜索即可。
此外还有一点可优化:因为要求输出使用饲料的最小数量,所以可以进行特判,当搜索的次数大于已经搜索到的最小次数时return即可。
代码如下:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 int V,v[31],G,g[31][31],ans=9999,n[31]; 6 bool flag,f[31],vitamin[31]; 7 void dfs(int num,int place) 8 { 9 if (num>=ans) return; 10 flag=true; 11 for (int i=1;i<=V;i++) 12 if (v[i]>n[i]) {flag=false; break;} 13 if (flag) 14 { 15 if (num<ans) 16 { 17 ans=num; 18 for (int i=1;i<=G;i++) 19 f[i]=vitamin[i]; 20 } 21 } 22 else 23 for (int i=place+1;i<=G;i++) 24 { 25 if (!vitamin[i]) 26 { 27 for (int j=1;j<=V;j++) 28 n[j]+=g[i][j]; 29 vitamin[i]=true; 30 dfs(num+1,i); 31 vitamin[i]=false; 32 for (int j=1;j<=V;j++) 33 n[j]-=g[i][j]; 34 } 35 } 36 } 37 int main() 38 { 39 //freopen("add.in","r",stdin); 40 //freopen("add.out","w",stdout); 41 memset(n,0,sizeof(n)); 42 memset(vitamin,false,sizeof(vitamin)); 43 memset(f,false,sizeof(f)); 44 scanf("%d",&V); 45 for (int i=1;i<=V;i++) 46 scanf("%d",&v[i]); 47 scanf("%d",&G); 48 for (int i=1;i<=G;i++) 49 for (int j=1;j<=V;j++) 50 scanf("%d",&g[i][j]); 51 dfs(0,0); 52 printf("%d ",ans); 53 for (int i=1;i<=G;i++) 54 if (f[i]) 55 printf("%d ",i); 56 return 0; 57 }