2014多校(1011)hdu4871

Shortest-path tree

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 130712/130712 K (Java/Others)
Total Submission(s): 407    Accepted Submission(s): 125


Problem Description
Given a connected, undirected graph G, a shortest-path tree rooted at vertex v is a spanning tree T of G, such that the path distance from root v to any other vertex u in T is the shortest path distance from v to u in G. 
We may construct a shortest-path tree using the following method:
We consider a shortest-path tree rooted at node 1. For every node i in the graph G, we choose a shortest path from root to i. If there are many shortest paths from root to i, we choose the one that the sequence of passing nodes' number is lexicographically minimum. All edges on the paths that we chose form a shortest-path tree.
Now we want to know how long are the longest simple paths which contain K nodes in the shortest-path tree and how many these paths? Two simple paths are different if the sets of nodes they go through are different.
 

Input
The first line has a number T (T <= 10), indicating the number of test cases.
For each test case, the first line contains three integers n, m, k(1<=n<=30000,1<=m<=60000,2<=k<=n), denote the number of nodes, the number of edges and the nodes of required paths.
Then next m lines, each lines contains three integers a, b, c(1<=a, b<=n, 1<=c<=10000),denote there is an edge between a, b and length is c.
 

Output
For each case, output two numbers, denote the length of required paths and the numbers of required paths.
 

Sample Input
   
   
1 6 6 4 1 2 1 2 3 1 3 4 1 2 5 1 3 6 1 5 6 1
 

Sample Output
   
   
3 4

第一次写树的分治,感觉又涨姿势了,哈哈~~~
思路:先求最短路树,我的方法是先按节点号从小到大插入邻接表,求出最短路后用DFS按节点号从小到大跑出最短路树(感觉这种方法还是太挫了,想不到更好的),
然后用树的分治求解,总体思路就是每次找到树的重心,然后以重心为中心(也就是说这条路径要经过中心)进行K个节点最大树链的求解,重心怎么求呢,可以去百度,这里不做介绍了。用一个pow[k]和pnum[k]数组维护当前分治求解的这颗树中的经过k个节点最大的路径长度和数量,然后每次从中心出发开拓新的子树的时候计数即可。

#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
         #include 
        
          #include 
         
           using namespace std; #define INF ((1<<31)-1) int n,m,k; int d; struct node{ int i; int d; node(int ii,int dd){i=ii;d=dd;} bool operator < (const node &a)const{return d>a.d;} }; struct vex{ int u; int v; int w; }; vex ve[60010]; priority_queue 
          
            q; vector 
           
             vv[30010]; int head[30010]; int edge[60010<<1]; int next[60010<<1]; int ww[60010<<1]; int dp[30010]; int vis[30010]; int head1[30010]; int edge1[60010]; int next1[60010]; int ww1[60010]; int num[30010]; int cnum[30010]; int center; int maxii; int total; int pow[30010]; int pnum[30010]; int val[30010]; int anss; int nanss; int maxi(int x,int y) { return x>y?x:y; } void add(int u,int v,int w) { edge[d]=v; ww[d]=w; next[d]=head[u]; head[u]=d++; } void add1(int u,int v,int w) { edge1[d]=v; ww1[d]=w; next1[d]=head1[u]; head1[u]=d++; } void djsk() { int i,temp; memset(vis,0,sizeof(vis)); for(i=1;i<=n;i++)dp[i]=INF; dp[1]=0; q.push(node(1,0)); while(!q.empty()) { node f=q.top(); q.pop(); if(vis[f.i])continue; vis[f.i]=1; for(i=head[f.i];i!=-1;i=next[i])if(dp[edge[i]]>(temp=dp[f.i]+ww[i])){ dp[edge[i]]=temp; q.push(node(edge[i],dp[edge[i]])); } } } void dfs(int u,int dis) { int i; vis[u]=1; for(i=head[u];i!=-1;i=next[i])if(!vis[edge[i]]&&dp[edge[i]]==dis+ww[i]){ // printf("%d %d\n",u,edge[i]); add1(u,edge[i],ww[i]); add1(edge[i],u,ww[i]); dfs(edge[i],dis+ww[i]); } } void dfs2(int u,int pre) { total++; num[u]=1; cnum[u]=0; int i; for(i=head1[u];i!=-1;i=next1[i])if(edge1[i]!=pre&&!val[edge1[i]]){ dfs2(edge1[i],u); num[u]+=num[edge1[i]]; if(cnum[u] 
            
              =k)return; vv[cent].push_back(dis); int temp; if((temp=dis+pow[k-1-cent])>anss) { // printf("%d %d %d haha\n",u,pow[k-1-cent],cent); anss=temp; nanss=pnum[k-1-cent]; } else if(temp==anss)nanss+=pnum[k-1-cent]; for(i=head1[u];i!=-1;i=next1[i])if(edge1[i]!=pre&&!val[edge1[i]])dfs4(edge1[i],u,dis+ww1[i],cent+1); } void diaozhatian(int u) { total=0; dfs2(u,0);//求出每个节点的子树节点数量和最大子树节点数量 if(total 
             
               pow[j]){ pow[j]=vv[j][kk]; // printf("\n%d %d\n\n",j,pow[j]); pnum[j]=1; } else if(vv[j][kk]==pow[j])pnum[j]++; } for(j=1;j<=k-1;j++)vv[j].clear(); } val[center]=1; for(i=head1[center];i!=-1;i=next1[i])if(!val[edge1[i]])diaozhatian(edge1[i]); } void solve() { djsk(); memset(pow,0,sizeof(pow)); memset(pnum,0,sizeof(pnum)); pnum[0]=1; memset(vis,0,sizeof(vis)); memset(val,0,sizeof(val)); d=0; dfs(1,0);//求出最短路树 // printf("\n"); diaozhatian(1);//树的分治 } bool cmp1(vex a,vex b) { if(a.u==b.u)return a.v>b.v; else return a.u 
              
                b.u; else return a.v 
                
               
              
             
            
           
          
         
       
      
      
     
     
    
    
   
   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值