NYOJ 1249 物资调度(DFS+剪枝)
题目链接:
http://acm.nyist.net/JudgeOnline/problem.php?pid=1249
描述
某地区发生了地震,灾区已经非常困难,灾民急需一些帐篷、衣物、食品和血浆等物资。可通往灾区的道路到处都是塌方,70%以上的路面损坏,桥梁全部被毁。国家立即启动应急预案,展开史上最大强度非作战空运行动,准备向灾区空投急需物资。
一方有难,八方支援。现在已知有N个地方分别有A1,A2,….,An个物资可供调配。目前灾区需要物资数量为M。
现在,请你帮忙算一算,总共有多少种物质调度方案。
假设某地方一旦被选择调配,则其物资数全部运走。
- 输入
- 输入一个组数T。(0<T<10)
之后为N,M含义分别如题目描述。(0<N<=100,0<M<=1000)
之后有N个数字A1,A2,….,An表示N个地方每个地方的物资数。(0<Ai<=1000) - 输出
- 对于每组测试数据,输出一行:物资调度的总方案数
- 样例输入
-
2 4 4 1 1 2 2 4 6 1 1 2 2
- 样例输出
-
3 1
- 来源 第七届河南省程序设计大赛
- 题意描述:
- 输入物资的堆数及所需调动的物资数、每堆物资数
- 计算并输出调度方案数
- 解题思路:
- 可以看成是有相同牌面的不同纸牌的排列,使用DFS的话,必定需要剪枝,因为全排列10张以上的牌速度就慢的可怕了(别说100张了),所以在搜索的时候向下传递i值,意即下次尝试的时候直接从后面取就行了,这样就避免了重复取牌。另外取的时候直接判断会不会超出限度,是的话直接剪掉。详见代码。
- AC代码:
1 #include<stdio.h> 2 #include<string.h> 3 void dfs(int step,int sum,int i); 4 int ans,n,v,book[110],a[110]; 5 int main() 6 { 7 int T,i,z; 8 scanf("%d",&T); 9 while(T--) 10 { 11 scanf("%d%d",&n,&v); 12 z=0;//物资总和 13 for(i=1;i<=n;i++) 14 { 15 scanf("%d",&a[i]); 16 z += a[i]; 17 } 18 if(z <= v) 19 { 20 if(z<v) 21 printf("0\n"); 22 else 23 printf("1\n"); 24 continue; 25 } 26 27 ans=0; 28 memset(book,0,sizeof(book)); 29 dfs(1,v,1);//向下传递放牌位置,所需物资数,取牌位置 30 printf("%d\n",ans); 31 } 32 return 0; 33 } 34 void dfs(int step,int sum,int i) 35 { 36 int j; 37 if(step==n+1 || sum ==0) 38 { 39 if(sum == 0) 40 ans++; 41 return; 42 } 43 for(;i<=n;i++) 44 { 45 if(sum < a[i])//必要剪枝 46 continue; 47 if(!book[i]) 48 { 49 book[i]=1; 50 sum -= a[i]; 51 dfs(step+1,sum,i+1); 52 53 book[i]=0; 54 sum += a[i]; 55 } 56 } 57 return ; 58 }
欢迎交流,共同进步——