[FJOI2014]最短路徑樹問題
題目描述
給一個包含$n$個點,$m$條邊的無向連通圖。從頂點$1$出發,往其他全部點分別走一次並返回。ui
往某一個點走時,選擇總長度最短的路徑走。如有多條長度最短的路徑,則選擇通過的頂點序列字典序最小的那條路徑(如路徑$A$爲$1,32,11$,路徑$B$爲$1,3,2,11$,路徑$B$字典序較小。注意是序列的字典序的最小,而非路徑中節點編號相連的字符串字典序最小)。到達該點後按原路返回,而後往其餘點走,直到全部點都走過。spa
能夠知道,通過的邊會構成一棵最短路徑樹。請問,在這棵最短路徑樹上,最長的包含$K$個點的簡單路徑長度爲多長?長度爲該最長長度的不一樣路徑有多少條?code
這裏的簡單路徑是指:對於一個點最多隻通過一次的路徑。不一樣路徑是指路徑兩端端點至少有一個不一樣,點$A$到點$B$的路徑和點$B$到點$A$視爲同一條路徑。排序
輸入輸出格式
輸入格式:
第一行輸入三個正整數$n$,$m$,$K$,表示有$n$個點$m$條邊,要求的路徑須要通過$K$個點。字符串
接下來輸入$m$行,每行三個正整數$A_i,B_i,C_i(1\le A_i,B_i\le n,1 \le C_i\le10000)$,表示$A_i$和$B_i$間有一條長度爲$C_i$的邊。string
數據保證輸入的是連通的無向圖。it
輸出格式:
輸出一行兩個整數,以一個空格隔開,第一個整數表示包含$K$個點的路徑最長爲多長,第二個整數表示這樣的不一樣的最長路徑有多少條。io
說明
對於全部數據$n\le30000,m\le60000$,$2\le K\le n$。class
數據保證最短路徑樹上至少存在一條長度爲K的路徑。sed
Solution
第二天然段的題意我如今都沒弄懂。
用個人理解就是先保證最短路,而後保證連邊的編號的字典序是最小的。
這個能夠先把最短路圖跑出來,而後對每一個點的出邊排序,從$1$開始跑$DFS$,邊跑邊連邊。
而後就是澱粉質了。
吐槽題意+強行拼題+寫起來不爽(不是爲了瞭解一下最短路樹我纔不寫呢)
複雜度$O(nlogn)$
Code:
#include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <queue> const int N=3e4+10; struct Edge { int v,w; bool friend operator <(Edge n1,Edge n2){return n1.v<n2.v;} }t; std::vector <Edge> e[N],e0[N]; int n,m,k; const int inf=0x3f3f3f3f; #define P std::pair <int,int> std::priority_queue <P,std::vector <P >,std::greater <P> > q; int dis[N],used[N]; int head[N],to[N<<1],edge[N<<1],Next[N<<1],cnt; void add(int u,int v,int w) { to[++cnt]=v,Next[cnt]=head[u],edge[cnt]=w,head[u]=cnt; } void disj() { memset(dis,0x3f,sizeof(dis)); q.push(std::make_pair(dis[1]=0,1)); while(!q.empty()) { int u=q.top().second; q.pop(); if(used[u]) continue; used[u]=1; for(int i=0;i<e[u].size();i++) { int v=e[u][i].v,w=e[u][i].w; if(dis[v]>dis[u]+w) { dis[v]=dis[u]+w; q.push(std::make_pair(dis[v],v)); } } } memset(used,0,sizeof(used)); } void dfsbuild(int now) { used[now]=1; for(int i=0;i<e0[now].size();i++) { int v=e0[now][i].v,w=e0[now][i].w; if(!used[v]) { add(now,v,w); add(v,now,w); dfsbuild(v); } } } void build() { for(int u=1;u<=n;u++) { for(int i=0;i<e[u].size();i++) { int v=e[u][i].v,w=e[u][i].w; if(dis[v]==dis[u]+w) t={v,w},e0[u].push_back(t); } std::sort(e0[u].begin(),e0[u].end()); } dfsbuild(1); } int ans,siz[N],rt,mi,mxlen[N],mx,del[N],td[N],tmxlen[N],scnt[N],tcnt[N]; int max(int x,int y){return x>y?x:y;} void dfsroot(int now,int fa,int sz) { siz[now]=1; int mx0=0; for(int i=head[now];i;i=Next[i]) { int v=to[i]; if(v==fa||del[v]) continue; dfsroot(v,now,sz); mx0=max(mx0,siz[v]); siz[now]+=siz[v]; } mx0=max(mx0,sz-siz[now]); if(mx0<mi) mi=mx0,rt=now; } void dfs(int now,int fa,int dis,int dep) { if(dep>k) return; if(mx<dis+mxlen[k-dep]) { mx=dis+mxlen[k-dep]; ans=scnt[k-dep]; } else if(mx==dis+mxlen[k-dep]) ans+=scnt[k-dep]; for(int i=head[now];i;i=Next[i]) { int v=to[i]; if(v==fa||del[v]) continue; dfs(v,now,dis+edge[i],dep+1); } if(tmxlen[dep]<dis) { tmxlen[dep]=dis; tcnt[dep]=1; } else if(tmxlen[dep]==dis) tcnt[dep]++; } void dfz(int now,int sz) { mi=1<<30; dfsroot(now,0,sz); now=rt; del[now]=1; for(int i=head[now];i;i=Next[i]) { int v=to[i]; if(del[v]) continue; dfs(v,now,edge[i],1); for(int j=1;tmxlen[j]!=-inf;j++) { if(tmxlen[j]>mxlen[j]) { scnt[j]=tcnt[j]; mxlen[j]=tmxlen[j]; } else if(tmxlen[j]==mxlen[j]) scnt[j]+=tcnt[j]; tcnt[j]=0,tmxlen[j]=-inf; } } if(mx<mxlen[k]) ans=scnt[k],mx=mxlen[k]; else if(mx==mxlen[k]) ans+=scnt[k]; for(int i=1;mxlen[i]!=-inf;i++) mxlen[i]=-inf; for(int i=head[now];i;i=Next[i]) if(!del[to[i]]) dfz(to[i],siz[to[i]]); } int main() { //freopen("data.in","r",stdin); //freopen("wr.out","w",stdout); scanf("%d%d%d",&n,&m,&k); for(int u,v,w,i=1;i<=m;i++) { scanf("%d%d%d",&u,&v,&w); t={v,w}; e[u].push_back(t); t={u,w}; e[v].push_back(t); } disj(); build(); --k; for(int i=0;i<=k+1;i++) tmxlen[i]=mxlen[i]=-inf; dfz(1,n); printf("%d %d\n",mx,ans); return 0; }
2018.10.22