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
");
22             else
23             printf("1
");
24             continue;
25         }    
26         
27         ans=0;
28         memset(book,0,sizeof(book));
29         dfs(1,v,1);//向下传递放牌位置,所需物资数,取牌位置 
30         printf("%d
",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 }
原文地址:https://www.cnblogs.com/wenzhixin/p/7412323.html