这里拿C++一本通(白书第三版)上DFS的课后题12最佳调度问题举例子。(没看过题去自己翻书)
这是光盘里附带的标程:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 int n,k,a[101],f[1001],ans; 6 void find(int x,int y) 7 { 8 int i; 9 if (y>=ans) return; 10 if (x>n) 11 { 12 if (y<ans) ans=y; 13 return; 14 } 15 for(i=1;i<=k;i++) 16 { 17 f[i]=f[i]+a[x]; 18 find(x+1,max(y,f[i])); 19 f[i]=f[i]-a[x]; 20 } 21 } 22 int main() 23 { 24 int i; 25 scanf("%d%d",&n,&k); 26 for(i=1;i<=n;i++) 27 scanf("%d",&a[i]); 28 memset(f,0,sizeof(f)); 29 ans=2147483647; 30 find(1,0); 31 printf("%d",ans); 32 }
然后我们拿一组附带的测试数据:
in
19 4
21 60 24 44 81 71 42 9 51 56 41 79 23 60 85 86 72 10 15
out
233
就发现标程T了= =
我们改一改标程,加上点玄学优化:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 int n,k,a[101],f[1001],ans; 6 void find(int x,int y) 7 { 8 int i; 9 if (y>=ans) return; 10 if (x>n) 11 { 12 if (y<ans) ans=y; 13 return; 14 } 15 for(i=1;i<=k;i++) 16 { 17 f[i]=f[i]+a[x]; 18 find(x+1,max(y,f[i])); 19 f[i]=f[i]-a[x]; 20 } 21 } 22 int main() 23 { 24 int i; 25 scanf("%d%d",&n,&k); 26 for(i=1;i<=n;i++) 27 scanf("%d",&a[i]); 28 sort(a+1,a+1+n); 29 reverse(a+1,a+1+n); 30 memset(f,0,sizeof(f)); 31 ans=2147483647; 32 find(1,0); 33 printf("%d",ans); 34 }
相比标程,改动后的程序只在28,29两行加了个sort排序并且反了过来。(reverse是把数组里的元素改成逆序,就是把sort排完序的从小到大改成从大到小,你写个自定义比较函数也OK)
然后= =神奇的事情就发生了,跑的比标程快多了2333。
对于搜索的优化,除了对初始数据进行排序(从大到小和从小到大的结果是不一样的,比如这个题如果你是按从小到大排再搜索依旧是TLE),还可以在搜索前进行一次贪心,先认为你的贪心结果是对的,这样的话就算贪到的结果不是正解,也比较接近正解,这样在搜索的时候比你贪到的答案大的就可以直接跳过了。(当然你要考虑你贪心的时间复杂度,不要贪来贪去贪的慢。)