樹的分治 FJOI2014最短路徑樹問題

2021-06-21 08:12:58 字數 1629 閱讀 7491

【題目大意】給乙個包含n個點,m條邊的無向連通圖。從頂點1出發,往其餘所有點分別走一次並返回。

往某乙個點走時,選擇總長度最短的路徑走。若有多條長度最短的路徑,則選擇經過的頂點序列字典序最小的那條路徑(如路徑a為1,32,11,路徑b為1,3,2,11,路徑b字典序較小。注意是序列的字典序的最小,而非路徑中節點編號相連的字串字典序最小)。到達該點後按原路返回,然後往其他點走,直到所有點都走過。

可以知道,經過的邊會構成一棵最短路徑樹。請問,在這棵最短路徑樹上,最長的包含k個點的簡單路徑長度為多長?以及長度為該最長長度的不同簡單路徑有多少條?

這裡的簡單路徑是指:對於乙個點最多隻經過一次的路徑。不同路徑是指路徑兩端端點至少有乙個不同,點a到點b的路徑和點b到點a視為同一條路徑。

【題解】今天太晚了以後再寫

#include#include#include#include#define fo(i,a,b) for (int i = a;i <= b;i ++)

using namespace std;

const int maxn = 30005;

int n,m,k,ans,sum,root,size,cnt;

int s[maxn],f[maxn];

struct graph

old,new;

struct t

return l;

}};void graph::insert(int x,int y,int z)

void graph::spfa()}}

bz[x] = 0;

} fo(i,2,n) }

void graph::findroot(int x,int last)

f[x] = max(f[x],size-s[x]);

if (f[x] < f[root]) root = x;

}t tank[maxn];

inline void update(int x,int _l,int time)

else

if (_l == tank[x].l)

tank[x].n ++;

} else

tank[x].t = time;

}inline void upd_ans(int l,int cnt)

else

if (l == ans) sum += cnt;

}void graph::collect(int x,int dep,int len,int last,int time)

void graph::dfs(int x,int dep,int len,int last,int time)

void graph::work(int x,int t)

flag[x] = 1;

for (int i = a[x];i;i = c[i])

if (!flag[b[i]]) }

int main()

old.spfa();

f[0] = size = n;

new.findroot(1,root = 0);

new.work(root,cnt = 1);

printf("%d %d\n",ans,sum);

return 0;

}

FJOI2014最短路徑樹問題

給乙個包含n個點,m條邊的無向連通圖。從頂點1出發,往其餘所有點分別走一次並返回。往某乙個點走時,選擇總長度最短的路徑走。若有多條長度最短的路徑,則選擇經過的頂點序列字典序最小的那條路徑 如路徑a為1,32,11,路徑b為1,3,2,11,路徑b字典序較小。注意是序列的字典序的最小,而非路徑中節點編...

FJOI2014 最短路徑樹問題

here 吐槽一下這個題,完全就是兩個裸題拼一起了,而且兩個板子之間毫無聯絡 首先我們造乙個保證字典序最小的最短路徑樹,怎麼保證字典序呢,先將你存的圖按字典序從小到大重新排個序再跑最短路就行了。之後就是 跑 dijkstra dfs 一遍重新建圖,如果 u 已經被訪問過,那麼邊 e 在最短路上的當且...

FJOI2014 最短路徑樹問題

這題已經在我的收藏夾裡吃了大半年的灰了 主要是因為他們有人把這題歸到了樹形dp裡面,然後我就傻乎乎地把它收藏了 首先,假設我們已經求出了這個 最短路徑樹 剩下的就是點分治的板子了。而這個 最短路徑樹 首先可以通過dijkstra跑出最短路徑dag,然後在dag上用bfs即可求出字典序最小的樹。總的來...