zoukankan      html  css  js  c++  java
  • [BZOJ4016]最短路径树问题

    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

    设$f[i][0/1]$表示到当前分治重心的路径中点数为$i$的路径最大长度和方案数

    然后注意细节就可以$A$掉它了

    代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<queue>
      5 #include<vector>
      6 #include<cstring>
      7 #define M 100010
      8 #define inf 1e9
      9 using namespace std;
     10 int n,m,num,ans1,ans2,S,rt,k;
     11 int head[M],dis[M],d[M],g[M],size[M],maxn[M],f[M][2];
     12 bool vis[M];
     13 struct point{int to,next,dis;}e[M<<1];
     14 struct edge{int to,dis;};
     15 struct node{int id,v;};
     16 vector<edge>vec[M];
     17 priority_queue<node>Q;
     18 bool operator < (node a1,node a2) {
     19     return a1.v>a2.v;
     20 }
     21 void add(int from,int to,int dis) {
     22     e[++num].next=head[from];
     23     e[num].to=to;
     24     e[num].dis=dis;
     25     head[from]=num;
     26 }
     27 void Dijkstra(int s) {
     28     memset(dis,63,sizeof(dis));
     29     dis[s]=0;
     30     Q.push((node){s,0});
     31     while(!Q.empty()) {
     32         int x=Q.top().id;Q.pop();
     33         if(vis[x]) continue;
     34         for(int i=0;i<vec[x].size();i++) {
     35             int to=vec[x][i].to;
     36             if(dis[to]>dis[x]+vec[x][i].dis) {
     37                 dis[to]=dis[x]+vec[x][i].dis;
     38                 Q.push((node){to,dis[to]});
     39             }
     40         }
     41     }
     42 }
     43 void build(int x) {
     44     vis[x]=true;
     45     for(int i=0;i<vec[x].size();i++) {
     46         int to=vec[x][i].to;
     47         if(vis[to]) continue;
     48         if(dis[x]+vec[x][i].dis==dis[to]) {
     49             build(to);
     50             add(x,to,vec[x][i].dis);
     51             add(to,x,vec[x][i].dis);
     52         }
     53     }
     54 }
     55 void getroot(int x,int fa) {
     56     size[x]=1;maxn[x]=0;
     57     for(int i=head[x];i;i=e[i].next) {
     58         int to=e[i].to;
     59         if(to==fa||vis[to]) continue;
     60         getroot(to,x),size[x]+=size[to];
     61         maxn[x]=max(maxn[x],size[to]);
     62     }
     63     maxn[x]=max(maxn[x],S-size[x]);
     64     if(maxn[x]<maxn[rt]) rt=x;
     65 }
     66 void cal(int x,int fa) {
     67     if(d[x]>k) return;
     68     if(ans1<g[x]+f[k-d[x]+(d[x]!=k)][0]) ans1=g[x]+f[k-d[x]+(d[x]!=k)][0],ans2=f[k-d[x]+(d[x]!=k)][1];
     69     else if(ans1==g[x]+f[k-d[x]+(d[x]!=k)][0]) ans2+=f[k-d[x]+(d[x]!=k)][1];
     70     for(int i=head[x];i;i=e[i].next) {
     71         int to=e[i].to;
     72         if(to==fa||vis[to]) continue;
     73         d[to]=d[x]+1,g[to]=g[x]+e[i].dis;
     74         cal(to,x);
     75     }
     76 }
     77 void insert(int x,int fa) {
     78     if(d[x]<=k) {
     79         if(f[d[x]][0]<g[x]) f[d[x]][0]=g[x],f[d[x]][1]=1;
     80         else if(f[d[x]][0]==g[x]) f[d[x]][1]++;
     81         for(int i=head[x];i;i=e[i].next)
     82             if(!vis[e[i].to]&&e[i].to!=fa)
     83                 insert(e[i].to,x);
     84     }
     85 }
     86 void del(int x,int fa) {
     87     if(d[x]<=k) {
     88         f[d[x]][0]=f[d[x]][1]=-inf;
     89         for(int i=head[x];i;i=e[i].next)
     90             if(!vis[e[i].to]&&e[i].to!=fa)
     91                 del(e[i].to,x);
     92     }
     93 }
     94 void solve(int x) {
     95     //cout<<x<<endl;
     96     vis[x]=true;f[0][0]=0,f[0][1]=1;
     97     for(int i=head[x];i;i=e[i].next) {
     98         int to=e[i].to;
     99         if(vis[to]) continue;
    100         d[to]=2,g[to]=e[i].dis,cal(to,x);
    101         insert(to,x);
    102     }
    103     for(int i=head[x];i;i=e[i].next)
    104         if(!vis[e[i].to])
    105             del(e[i].to,x);
    106     for(int i=head[x];i;i=e[i].next) {
    107         int to=e[i].to;
    108         if(vis[to]) continue;
    109         S=size[to],rt=0,getroot(to,0);
    110         solve(rt);
    111     }
    112 }
    113 int main() {
    114     scanf("%d%d%d",&n,&m,&k);
    115     memset(f,128,sizeof(f));
    116     for(int i=1;i<=m;i++) {
    117         int a,b,c;scanf("%d%d%d",&a,&b,&c);
    118         vec[a].push_back((edge){b,c});
    119         vec[b].push_back((edge){a,c});
    120     }
    121     Dijkstra(1),memset(vis,0,sizeof(vis)),build(1);
    122     memset(vis,0,sizeof(vis)),maxn[0]=S=n,getroot(1,0);
    123     solve(rt);printf("%d %d",ans1,ans2);
    124     return 0;
    125 }
  • 相关阅读:
    列出本年度所有星期天的日期
    批量与快速禁用用户
    显示本月每一天日期
    ASP.NET + VB.NET + SQL小网站程序
    重设Syteline sa帐户密码
    ASP.NET系统 + Access数据库
    2的倍数相加后如何还原
    根据Forms名找出其所归属的权限组
    401 Unauthorized:access is denied due to invalied credentials
    The remote server returned an error: (404) Not Found
  • 原文地址:https://www.cnblogs.com/Slrslr/p/10028993.html
Copyright © 2011-2022 走看看