引用請註明出處:http://www.cnblogs.com/lihaiping/p/7799495.htmlhtml
最近項目開發中遇到一個和找零錢很類似的問題,因此網上搜索了一下,大部分的問題,都是關於如何求出找零錢的方法數(有多少種找零的方法)和如何求少找零的方案。算法
但我此次的問題,須要在求出找零錢方法數的同時還須要求出這些方法中的每種具體找零方法。數組
根據網上的代碼,求找零方法數種類:(動態規劃的算法)數據結構
1 int countWays(vector<int> changes, int n, int x) { 2 // 待兌換的金額是i,可用的範圍是0-j-1 3 // i = x,j = 0-n-1 4 //int dp[x+1][n]; 5 6 //使用動態開闢二維數組 7 int **dp = new int*[x+1]; 8 for(int i=0;i<(x+1);i++) 9 { 10 dp[i] = new int[n]; 11 memset(dp[i],0,n*sizeof(int)); 12 } 13 // 當待兌換的金額是0的時候,都是隻有一種,就是空集 14 for(int i=0;i<n;i++){// 15 dp[0][i] = 1; 16 } 17 18 // 第1列,待兌換的錢是i,由於只能用第一種零錢,因此只有當是第一種零錢的整數倍的時候,纔有一種兌換方法 19 for (int i = 1; i <= x; i++) { 20 if (i % changes[0] == 0) { 21 dp[i][0] = 1; 22 } 23 } 24 for (int i = 1; i <= x; i++) 25 { 26 for (int j = 1; j < n; j++) 27 { 28 if (i - changes[j] >= 0) 29 { 30 dp[i][j] += (dp[i][j-1] + dp[i - changes[j]][j]); 31 } 32 else{ 33 dp[i][j] += dp[i][j-1]; 34 } 35 } 36 } 37 int count=dp[x][n-1]; 38 39 40 for(int k=0;k<(x+1);k++) 41 delete []dp[k]; 42 43 delete []dp; 44 45 return count; 46 }
下面爲我改造求找零方法數的同時並記錄下找零的具體方法:測試
1 //map<待兌換金額,map<所用找零的面值,找零具體方案vector<vector<int> > >> 2 map<int,map<int,vector<vector<int> > > > mapAimChanges; 3 4 int countWaysEx(vector<int> changes, int n, int x) { 5 // 待兌換的金額是i,可用的範圍是0-j-1 6 // i = x,j = 0-n-1 7 //int dp[x+1][n]; 8 9 //使用動態開闢二維數組 10 int **dp = new int*[x+1]; 11 for(int i=0;i<(x+1);i++) 12 { 13 dp[i] = new int[n]; 14 memset(dp[i],0,n*sizeof(int)); 15 } 16 17 18 19 // 當待兌換的金額是0的時候,都是隻有一種,就是空集 20 for(int i=0;i<n;i++){// 21 dp[0][i] = 1; 22 } 23 //mapAimChanges.insert(pair<int,map<int,vector<vector<int> > > >(0,mapVecVecTemp_0)); 24 25 // 第1列,待兌換的錢是i,由於只能用第一種零錢,因此只有當是第一種零錢的整數倍的時候,纔有一種兌換方法 26 for (int i = 1; i <= x; i++) { 27 if (i % changes[0] == 0) { 28 //一維數組,具體找零方案 29 vector<int> vecTemp(i/changes[0],changes[0]); 30 //找零方案的組合,造成一個二維數組 31 vector<vector<int> > vecvecTemp(1,vecTemp); 32 //存儲所用零錢 33 map<int,vector<vector<int> > > mapVecVecTemp; 34 mapVecVecTemp.insert(pair<int,vector<vector<int> > >(0,vecvecTemp)); 35 36 mapAimChanges.insert(pair<int,map<int,vector<vector<int> > > >(i,mapVecVecTemp)); 37 38 dp[i][0] = 1; 39 } 40 } 41 for (int i = 1; i <= x; i++) 42 { 43 for (int j = 1; j < n; j++) 44 { 45 if (i - changes[j] >= 0) 46 { 47 //找零方案的組合,二維數組 48 vector<vector<int> > vecvecTempGoup; 49 //存儲所用零錢索引j的找零方案組合 50 map<int,vector<vector<int> > > mapVecVecTemp; 51 52 map<int,map<int,vector<vector<int> > > >::iterator iter1=mapAimChanges.find(i); 53 if (iter1!=mapAimChanges.end()) 54 { 55 mapVecVecTemp=iter1->second;//進行一次拷貝,防止後續在earse的時候出現其餘內容的丟失 56 //查找上一個索引j-1 57 map<int,vector<vector<int> > >::iterator iter2=iter1->second.find(j-1); 58 if (iter2!=iter1->second.end()) 59 {//若是找到 60 //先把j-1的內容拷貝 61 vecvecTempGoup=iter2->second; 62 } 63 } 64 65 //添加新的方案 66 vector<vector<int> > vecvecTemp2;//新的找零二維數組方案 67 iter1=mapAimChanges.find(i - changes[j]);//查找以前對i-change[j]的找零方案 68 if (iter1!=mapAimChanges.end()) 69 { 70 //查找上一個索引j 71 map<int,vector<vector<int> > >::iterator iter2=iter1->second.find(j); 72 if (iter2!=iter1->second.end()) 73 {//若是找到 74 //對於i-changes[j]的零錢在j這個索引上所用的全部找零方案, 75 //咱們須要在以前的基礎上插入一個新的元素changes[i],造成一個新的找零方案 76 vector<vector<int> > vecvecTemp; 77 vecvecTemp=iter2->second; 78 79 vector<vector<int> >::iterator vecvecIter3=vecvecTemp.begin(); 80 for (;vecvecIter3!=vecvecTemp.end();vecvecIter3++) 81 { 82 vector<int> vecTemp=*vecvecIter3; 83 vecTemp.push_back(changes[j]); 84 //將生成的新找零方案,放入二維數組 85 vecvecTemp2.push_back(vecTemp); 86 } 87 } 88 } 89 else//說明找到的是爲空集 90 {//說明i - changes[j]==0,纔會爲空集 91 vector<int> vecTemp_0(1,changes[j]); 92 vecvecTemp2.push_back(vecTemp_0); 93 } 94 95 if (!vecvecTemp2.empty()) 96 { 97 vecvecTempGoup.insert(vecvecTempGoup.end(),vecvecTemp2.begin(),vecvecTemp2.end()); 98 } 99 if (!vecvecTempGoup.empty()) 100 { 101 mapVecVecTemp.erase(j); 102 mapVecVecTemp.insert(pair<int,vector<vector<int> > >(j,vecvecTempGoup)); 103 mapAimChanges.erase(i); 104 mapAimChanges.insert(pair<int,map<int,vector<vector<int> > > >(i,mapVecVecTemp)); 105 } 106 107 108 dp[i][j] += (dp[i][j-1] + dp[i - changes[j]][j]); 109 } 110 else{ 111 //找零方案的組合,二維數組 112 vector<vector<int> > vecvecTemp; 113 map<int,map<int,vector<vector<int> > > >::iterator iter1=mapAimChanges.find(i); 114 if (iter1!=mapAimChanges.end()) 115 { 116 //存儲所用零錢索引j的找零方案組合 117 map<int,vector<vector<int> > > mapVecVecTemp=iter1->second; 118 //查找上一個索引 119 map<int,vector<vector<int> > >::iterator iter2=iter1->second.find(j-1); 120 if (iter2!=iter1->second.end()) 121 {//若是找到 122 vecvecTemp=iter2->second; 123 mapVecVecTemp.insert(pair<int,vector<vector<int> > >(j,vecvecTemp)); 124 125 //map操做的時候,相同的key的時候,會出現insert失敗,而不是覆蓋 126 //因此這裏須要先進行刪除 127 mapAimChanges.erase(i); 128 //mapAimChanges.erase(iter1); 129 mapAimChanges.insert(pair<int,map<int,vector<vector<int> > > >(i,mapVecVecTemp)); 130 } 131 } 132 dp[i][j] += dp[i][j-1]; 133 } 134 } 135 } 136 int count=dp[x][n-1]; 137 138 139 for(int k=0;k<(x+1);k++) 140 delete []dp[k]; 141 142 delete []dp; 143 144 return count; 145 }
下面爲測試的代碼:優化
1 vector<int> vecRmb; 2 vecRmb.push_back(1); 3 vecRmb.push_back(2); 4 vecRmb.push_back(3); 5 6 int ret=countWays(vecRmb,vecRmb.size(),5); 7 printf("ret=%d\n",ret); 8 9 ret=countWaysEx(vecRmb,vecRmb.size(),5); 10 printf("ret=%d\n",ret); 11 map<int,map<int,vector<vector<int> > > >::iterator map_iter=mapAimChanges.find(5); 12 if (map_iter!=mapAimChanges.end()) 13 { 14 map<int,vector<vector<int> > >::iterator map_iter2=map_iter->second.find(vecRmb.size()-1); 15 if (map_iter2!=map_iter->second.end()) 16 { 17 vector<vector<int> >::iterator vec_vec_iter3=map_iter2->second.begin(); 18 printf("size:%d\n",map_iter2->second.size()); 19 for (;vec_vec_iter3!=map_iter2->second.end();vec_vec_iter3++) 20 { 21 vector<int> vecTemp=*vec_vec_iter3; 22 for (int i=0;i<vecTemp.size();i++) 23 { 24 printf("["); 25 printf(" %d ",vecTemp.at(i)); 26 printf("]"); 27 } 28 printf("\n"); 29 } 30 } 31 32 }
打印結果:spa
其中方法和數據結構沒有進行優化,若是有優化的方法,各位能夠提出來,咱們一塊兒改造這個經典問題。code