題目鏈接:
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 }