BZOJ 4016: [FJOI2014]最短路径树问题

4016: [FJOI2014]最短路径树问题

Time Limit: 5 Sec  Memory Limit: 512 MB
Submit: 845  Solved: 309
[Submit][Status][Discuss]

Description

给一个包含n个点,m条边的无向连通图。从顶点1出发,往其余所有点分别走一次并返回。
往某一个点走时,选择总长度最短的路径走。若有多条长度最短的路径,则选择经过的顶点序列字典序最小的那条路径(如路径A为1,32,11,路径B为1,3,2,11,路径B字典序较小。注意是序列的字典序的最小,而非路径中节点编号相连的字符串字典序最小)。到达该点后按原路返回,然后往其他点走,直到所有点都走过。
可以知道,经过的边会构成一棵最短路径树。请问,在这棵最短路径树上,最长的包含K个点的简单路径长度为多长?长度为该最长长度的不同路径有多少条?
这里的简单路径是指:对于一个点最多只经过一次的路径。不同路径是指路径两端端点至少有一个不同,点A到点B的路径和点B到点A视为同一条路径。
 

 

Input

第一行输入三个正整数n,m,K,表示有n个点m条边,要求的路径需要经过K个点。接下来输入m行,每行三个正整数Ai,Bi,Ci(1<=Ai,Bi<=n,1<=Ci<=10000),表示Ai和Bi间有一条长度为Ci的边。数据保证输入的是连通的无向图。
 

 

Output

输出一行两个整数,以一个空格隔开,第一个整数表示包含K个点的路径最长为多长,第二个整数表示这样的不同的最长路径有多少条。
 

 

Sample Input

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

HINT

 

对于所有数据n<=30000,m<=60000,2<=K<=n。数据保证最短路径树上至少存在一条长度为K的路径。


 

 

 

Source

 

[Submit][Status][Discuss]

解析:

先用dijkstra跑出最短路网,然后在最短路网上对于每个节点按照孩子编号从小到大跑dfs,就可以得到题意描述中的那棵树。 
对于这棵树,定义状态f[i][j]表示从i号点出发经过j个点的最长路径长度,g[i][j]表示最长路径的数量。
转移,分为子数内和跨越子数转移。 
优化:在一棵子数内,一条路径只能是向下延伸或跨越2个子树,对于前者dfs解决,对于后者,这显然是一个可以分治的问题,用点分治可以把复杂度降到O(nlogn)即可。

AC代码:

//调了3个小时,不缩行了,直接扔这了 
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define pir pair<int,int>
using namespace std;
const int N=1e5+10;
vector<pir>G[N];
int n,m,mv,cnt,root,siz,K;
int s[N],froot,f[2][N],g[2][N];
bool vis[N];
int to[N<<1],nxt[N<<1],head[N],W[N<<1],totE;;
#define add(a,b,c) (to[++totE] = b, nxt[totE] = head[a], W[totE] = c, head[a] = totE)
int d[N]; 
void dijkstra(){
    priority_queue<pir,vector<pir>,greater<pir> >q;
    memset(d,127,sizeof d);
    q.push(make_pair(d[1]=0,1));
    int p,dis,w,v;
    while(!q.empty()){
        pir h=q.top();q.pop();
        dis=h.first;
        p=h.second;
        if(d[p]^dis) continue;
        sort(G[p].begin(),G[p].end());
        for(int i=0;i<G[p].size();i++){
            if(d[v=G[p][i].first]>dis+(w=G[p][i].second)){
                q.push(make_pair(d[v]=dis+w,v)); 
            }
        }
    }
}
void Build(int u){
    int v;
    vis[u]=1;
    for(int i=0;i<G[u].size();i++){
        if(!vis[v=G[u][i].first]&&d[v]==d[u]+G[u][i].second){
            add(v,u,G[u][i].second);
            add(u,v,G[u][i].second);
            Build(v);
        }
    }
}
void getroot(int u,int fa){
    s[u]=1;
    int mx=0,v;
    for(int it=head[u];it;it=nxt[it]){
        if(!vis[v=to[it]]&&(v^fa)){
            getroot(v,u);
            s[u]+=s[v];
            if(s[v]>mx) mx=s[v];
        }
         
    }
    if(siz-mx>mx) mx=siz-mx;
    if(froot>mx) root=u,froot=mx;
}
void dfs(int u,int fa,int dep){
    if(dep>K) return ;
    int v;
    if(d[u]>g[0][dep]) g[0][dep]=d[u],g[1][dep]=0;
    if(d[u]>=g[0][dep]) g[1][dep]++;
    for(int i=head[u];i;i=nxt[i]){
        if(!vis[v=to[i]]&&(v^fa)){
          d[v]=d[u]+W[i];
          dfs(v,u,dep+1);
        }
    }
     
}
void solve(int u,int S){
    vis[u]=1;
    f[0][0]=0;
    f[1][0]=1;
    int v;
    for(int i=head[u];i;i=nxt[i]){
        if(!vis[v=to[i]]){
            d[v]=W[i];
            dfs(v,u,1);
            for(int j=1;j<=K;j++){
                if(g[0][j]+f[0][K-j]>mv) mv=g[0][j]+f[0][K-j],cnt=0;
                if(g[0][j]+f[0][K-j]>=mv) cnt+=g[1][j]*f[1][K-j];
            }
            for(int j=1;j<=K;j++){
                if(g[0][j]>f[0][j]) f[0][j]=g[0][j],f[1][j]=0;
                if(g[0][j]>=f[0][j]) f[1][j]+=g[1][j];
                g[0][j]=g[1][j]=0;
            }
        }
    }
    for(int i=0;i<=K;i++) f[0][i]=f[1][i]=0;
    for(int i=head[u];i;i=nxt[i]){
        if(!vis[v=to[i]]){
            froot=siz=s[v];
            root=0;
            getroot(v,u);
            solve(root,s[v]);
        }
    }
}
int main(){
    scanf("%d%d%d",&n,&m,&K);--K;
    for(int a,b,c,i=1;i<=m;i++){
        scanf("%d%d%d",&a,&b,&c);
        G[a].push_back(make_pair(b,c)); 
        G[b].push_back(make_pair(a,c)); 
    }
    dijkstra();
    Build(1);
    memset(vis,0,sizeof vis);
    froot=siz=n;
    getroot(1,root=0);
    solve(root,n);
    printf("%d %d\n",mv,cnt);
    return 0;
} 

 

 

 

posted @ 2016-11-07 21:17  神犇(shenben)  阅读(282)  评论(0编辑  收藏  举报