Given a non-empty tree with root R, and with weight Wi assigned to each tree node Ti. The weight of a path from R to L is defined to be the sum of the weights of all the nodes along the path from R to any leaf node L.
Now given any weighted tree, you are supposed to find all the paths with their weights equal to a given number. For example, let's consider the tree showed in the following figure: for each node, the upper number is the node ID which is a two-digit number, and the lower number is the weight of that node. Suppose that the given number is 24, then there exists 4 different paths which have the same given weight: {10 5 2 7}, {10 4 10}, {10 3 3 6 2} and {10 3 3 6 2}, which correspond to the red edges in the figure.
來吧,讓我詳細翻譯一下題意吧。
給一個r個結點的非空樹,並且每個節點ti的權重爲wi,從R節點到L節點的路途權重=途中各個節點的權重和。
現在給出一個加權樹,你應該找到所有的路徑權重=一個給定的數字。讓我們考慮以下圖中的樹。
每個節點的ID是一個兩位數,每個圓圈中橫線下面的數字是該節點的權重。假設給定的數字是24。
那麼存在4不同的路徑也有相同的給定的重量:{ 10 5 2 7 },{ 10 4 },{ 10 3 3 6 2 }和{ 10 3 3 6 2 },這對應於圖中的紅色邊。
input:
第一行爲 N結點個數 M非葉節點數,也就算是子樹的樹根 S樹的子路徑的權值和
下一行給出每個結點的權重,順序是從結點1-N
再下M行是
:每個子樹樹根的結點 直接相連的子節點的個數 每個直接相連的點
如:
20 9 24
10 2 4 3 5 10 2 18 9 7 2 2 1 3 12 1 8 6 2 2
00 4 01 02 03 04
02 1 05
04 2 06 07
03 3 11 12 13
06 1 09
07 2 08 10
16 1 15
13 3 14 16 17
17 2 18 19
Sample Output:
按字典序從大到小的輸出每一個符合條件的子路徑,每行一個
如:
10 5 2 7
10 4 10
10 3 3 6 2
10 3 3 6 2
再次提示:由於這是考研題,所以每個變量的數據量不算特別大,才10^6的樣子,放心大膽地拿vector建圖就行,不用什麼前向星連式存儲省內存,放心大膽地vector和dfs的莽吧!
題目大意:給出樹的結構和權值,找從根結點到葉子結點的路徑上的權值相加之和等於給定目標數的路徑,並且從大到小輸出路徑
思路:
這道題還是很oK的,用鄰接表方式儲存子節點,並對每個父節點所有的子節點按權重排序。
再用dfs,在dfs中保存路徑,當dfs到葉節點時,即該節點的鄰接表爲空時,判斷該條路徑的和是否與題目要求的相等,相等則輸出路徑。
注意在每次對一個節點的所有鄰接表中的節點訪問後,就要pop出,sum也要減去相應節點的weight,以維持路徑和sum的正確性。
代碼:利用vector存儲的dfs的寫法!
#include #include #include using namespace std; int weight[101],n,m,s,father,son,num; vector<int>list[101],res; int sum=0; int cmp(int n,int m)//按權值升序排序 { return weight[n]>weight[m];} void dfs(int root,int n) { res.push_back(weight[root]); sum+=weight[root];//每到一個節點就加上當前狀態的權值 if(list[root].size()==0)//到棧底的出棧操作 { if(sum==s) { for(int i=0;i<res.size();i++) i>0?(cout<<" "<<res[i]):(cout<<res[i]); cout<<endl; } sum-=res[res.size()-1]; res.pop_back(); return; } for(int i=0;i<list[root].size();i++) dfs(list[root][i],sum); sum-=res[res.size()-1];//晦朔 res.pop_back();//出棧,跳出當前節點 } int main() { cin>>n>>m>>s; for(int i=0;i<n;i++) cin>>weight[i];//每條邊的權值 for(int i=0;i<m;i++) { cin>>father>>num; for(int j=0;j<num;j++) { cin>>son; list[father].push_back(son);//利用vector存邊這是我比較愛用的手法 } //其實打比賽時數據結構的代碼手比較核心的問題就是“建立模型和存儲結構” sort(list[father].begin(),list[father].end(),cmp);//對同父節點的每條邊進行排序 } //以保障dfs時的輸出順序 dfs(0,0); return 0; } </num;j++) </m;i++) </n;i++) </res[i]); </res[i]):(</res.size();i++)
思路一樣!只不過是利用了stack和向前存儲的寫法!很好但我玩的不是很熟,但二者在時間空間複雜度上都差不多!
#include #include #include #include #include #include #include using namespace std; const int MAX = 101; int weigh[MAX]; map<int,vector<int> >adjlist; int pre[MAX]; stack<int> path; void print(int p){ while(p!=-1){ path.push(p); p = pre[p]; } printf("%d",weigh[path.top()]); path.pop(); while(!path.empty()){ printf(" %d",weigh[path.top()]); path.pop(); } printf("\n"); } void dfs(int p,const int s,int sum){ sum += weigh[p]; if(sum>s)return; if(sum==s && adjlist[p].empty()){//權值和等於s且爲葉子,打印路徑 print(p); return; } //說明到此處的權值和小於s,若p爲葉子,則返回,此路無解 if(adjlist[p].empty())return; //遍歷其各個孩子路徑 vector<int>::reverse_iterator ite = adjlist[p].rbegin(); for(;ite!=adjlist[p].rend();++ite){ dfs(*ite,s,sum); } } void init(int n){ int i; for(i=0;i<n;++i){ pre[i] = -1; } } bool cmp(int a,int b){ return weigh[a]<weigh[b]; } int main(){ //freopen("in.txt","r",stdin); int n,m,s,i,k,id,sid,ln; scanf("%d %d %d",&n,&m,&s); for(i=0;i<n;++i){ scanf("%d",&weigh[i]); } init(n); while(m--){ scanf("%d %d",&id,&ln); while(ln--){ scanf("%d",&sid); adjlist[id].push_back(sid); pre[sid] = id;//記錄節點的前驅,打印路徑時使用 } sort(adjlist[id].begin(),adjlist[id].end(),cmp); } dfs(0,s,0); return 0; } </n;++i){ </weigh[b]; </n;++i){