這道題有一個很經典的演算法。搜尋兩次,第一次記錄每一個節點最大的兩個值,記錄其中最大值的來源,第二次搜尋跟新每一個節點經過父親節點所能到大的最大值。最後從之前所記錄的值中找出最大值,就是題目中要求我們找的每一個節點最遠的傳輸距離。
推薦大家去看一篇文章《運用樹型動態規劃的解題思路和方法的探析》其中對記錄最大值的來源思想,有相關例題介紹。
Computer
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1112 Accepted Submission(s): 538
Problem DescriptionA school bought the first computer some time ago(so this computer's id is 1). During the recent years the school bought N-1 new computers. Each new computer was connected to one of settled earlier. Managers of school are anxious about
slow functioning of the net and want to know the maximum distance Si for which i-th computer needs to send signal (i.e. length of cable to the most distant computer). You need to provide this information.
Hint: the example input is corresponding to this graph. And from the graph, you can see that the computer 4 is farthest one from 1, so S1 = 3. Computer 4 and 5 are the farthest ones from 2, so S2 = 2. Computer 5 is the farthest one from 3, so S3 = 3. we also
get S4 = 4, S5 = 4.
InputInput file contains multiple test cases.In each case there is natural number N (N<=10000) in the first line, followed by (N-1) lines with descriptions of computers. i-th line contains two natural numbers - number of computer, to which
i-th computer is connected and length of cable used for connection. Total length of cable does not exceed 10^9. Numbers in lines of input are separated by a space.
OutputFor each case output N lines. i-th line must contain number Si for i-th computer (1<=i<=N).
Sample Input
51 12 13 11 1
Sample Output
32344
#include<iostream>#include<vector>#include<queue>#define MAXN 10100//樹形dp 經典 using namespace std;int n;bool visited[MAXN];int dp[3][MAXN]; // [0]最大 [1] 次大 [2] 經過父親節點的最大值 int longfrom[MAXN];class adj{public:int dis;int node;};typedef vector<adj> computer;computer c[MAXN];int max(int a,int b){return a>b?a:b;}void init(){memset(visited,0,sizeof(visited));memset(dp,0,sizeof(dp));memset(longfrom,0,sizeof(longfrom));}void dp1(int root) //dfs 第一次搜尋,儲存每一個結點最大值和次大值,並且記錄最大值的來源 {if(visited[root])return;visited[root]=true; dp[0][root]=0;dp[1][root]=0;dp[2][root]=0;longfrom[root]=0;for(int i=0;i<c[root].size();i++){int no=c[root][i].node;if(visited[no])continue;dp1(no);if(dp[0][root]<dp[0][no]+c[root][i].dis){dp[1][root]=dp[0][root]; //更新次大值 longfrom[root]=no; //記錄最大值的來源 dp[0][root]=dp[0][no]+c[root][i].dis; //更新最大值 }else{if(dp[1][root]<dp[0][no]+c[root][i].dis) //更新次大值 dp[1][root]=dp[0][no]+c[root][i].dis;}}} void dp2(int root) //bfs ,此處我才用的BFS,採用DFS也可以,貌似更加高效 {queue<int> ns;if(visited[root])return ;ns.push(root);while(!ns.empty()){int nn=ns.size();for(int i=0;i<nn;i++){int temp=ns.front();ns.pop();for(int j=0;j<c[temp].size();j++){int no=c[temp][j].node;if(!visited[no])ns.push(no);elsecontinue;if(no!=longfrom[temp]) //判斷父親節點的最大值的來源 dp[2][no]=max(dp[2][temp],dp[0][temp])+c[temp][j].dis; //父親節點最大值不經過當前節點,則選擇父親結點出最大值更新當前節點經過父親結點的最大值 elsedp[2][no]=max(dp[2][temp],dp[1][temp])+c[temp][j].dis; //否則選擇次大值更新 }visited[temp]=true;} }} int main(){while(cin>>n){init();for(int i=0;i<=n;i++)c[i].clear();for(int i=2;i<=n;i++){int to,l;adj news;cin>>to>>l;news.node=i;news.dis=l;c[to].push_back(news);news.node=to;c[i].push_back(news);}dp1(1); //一次搜尋 memset(visited,0,sizeof(visited));dp2(1); //二次搜尋更新最值 for(int i=1;i<=n;i++){cout<<max(dp[1][i],max(dp[0][i],dp[2][i]))<<endl; //選擇每個節點三個值的最大值 }}return 0;}