【最小树形图(奇怪的kruskal)】【SCOI 2012】【bzoj 2753】滑雪与时间胶囊
2753: [SCOI2012]滑雪與時(shí)間膠囊
Time Limit: 50 Sec Memory Limit: 128 MB Submit: 1621 Solved: 570Description
a180285非常喜歡滑雪。
他來到一座雪山,這里分布著M條供滑行的軌道和N個(gè)軌道之間的交點(diǎn)(同一時(shí)候也是景點(diǎn))。并且每一個(gè)景點(diǎn)都有一編號i(1<=i<=N)和一高度Hi。a180285能從景點(diǎn)i 滑到景點(diǎn)j 當(dāng)且僅當(dāng)存在一條i 和j 之間的邊,且i 的高度不小于j。
與其它滑雪愛好者不同,a180285喜歡用最短的滑行路徑去訪問盡量多的景點(diǎn)。
假設(shè)只訪問一條路徑上的景點(diǎn)。他會(huì)覺得數(shù)量太少。于是a180285拿出了他隨身攜帶的時(shí)間膠囊。這是一種非常奇妙的藥物,吃下之后能夠馬上回到上個(gè)經(jīng)過的景點(diǎn)(不用移動(dòng)也不被覺得是a180285 滑行的距離)。
請注意,這樣的奇妙的藥物是能夠連續(xù)食用的,即能夠回到較長時(shí)間之前到過的景點(diǎn)(比方上上個(gè)經(jīng)過的景點(diǎn)和上上上個(gè)經(jīng)過的景點(diǎn))。 如今,a180285站在1號景點(diǎn)望著山下的目標(biāo)。心潮澎湃。他十分想知道在不考慮時(shí)間
膠囊消耗的情況下,以最短滑行距離滑到盡量多的景點(diǎn)的方案(即滿足經(jīng)過景點(diǎn)數(shù)最大的前提下使得滑行總距離最小)。你能幫他求出最短距離和景點(diǎn)數(shù)嗎?
Input
輸入的第一行是兩個(gè)整數(shù)N。M。
接下來1行有N個(gè)整數(shù)Hi。分別表示每一個(gè)景點(diǎn)的高度。
接下來M行,表示各個(gè)景點(diǎn)之間軌道分布的情況。每行3個(gè)整數(shù),Ui,Vi。Ki。表示
編號為Ui的景點(diǎn)和編號為Vi的景點(diǎn)之間有一條長度為Ki的軌道。
Output
輸出一行,表示a180285最多能到達(dá)多少個(gè)景點(diǎn)。以及此時(shí)最短的滑行距離總和。
Sample Input
3 3 3 2 1 1 2 1 2 3 1 1 3 10Sample Output
3 2HINT
【數(shù)據(jù)范圍】
對于30%的數(shù)據(jù)。保證 1<=N<=2000 對于100%的數(shù)據(jù),保證 1<=N<=100000 對于全部的數(shù)據(jù)。保證 1<=M<=1000000,1<=Hi<=1000000000,1<=Ki<=1000000000。題解:
第一問就是要找有多少點(diǎn)和1聯(lián)通,直接bfs一邊就好了。
第二問實(shí)際上是求一個(gè)最小樹形圖(就是有向圖上的最小生成樹)。
一般都是用朱劉算法的。然而感覺不大會(huì)寫并且復(fù)雜度有些不正確,于是想了想kruskal。發(fā)現(xiàn)我們只須要對全部第一問中找出的點(diǎn)做就好了,所以能夠?qū)θ窟叞唇K點(diǎn)的高度降序和邊長升序排序就好了。這樣就能夠克服kruskal可能會(huì)做出來不聯(lián)通的樹了。
Code:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<algorithm> using namespace std; #define N 100100 #define M 2001000 #define LL long longstruct Edge{int u,v,next; LL k; }edge[M<<1]; int n,m,num=0,ans1,head[N],h[N],fa[N],q[M<<1]; LL ans2; bool vis[N];int in(){int x=0; char ch=getchar();while (ch<'0' || ch>'9') ch=getchar();while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();return x; } LL Lin(){LL x=0; char ch=getchar();while (ch<'0' || ch>'9') ch=getchar();while (ch>='0' && ch<='9') x=x*10+(LL)(ch-'0'),ch=getchar();return x; }void add(int u,int v,int k){edge[++num].u=u; edge[num].v=v; edge[num].k=k;edge[num].next=head[u]; head[u]=num; }void bfs(){int h=0,t=1; ans1=0;memset(vis,0,sizeof(vis));q[h]=1; vis[1]=1;while (h<t){int u=q[h++]; ans1++;for (int i=head[u]; i; i=edge[i].next){int v=edge[i].v;if (vis[v]) continue;q[t++]=v; vis[v]=1;}} }bool cmp(Edge x,Edge y){if (h[x.v]!=h[y.v]) return h[x.v]>h[y.v];return x.k<y.k; } int find(int x){if (x==fa[x]) return x;fa[x]=find(fa[x]);return fa[x]; } void unionn(int x,int y){fa[x]=y; } void kruskal(){ans2=0;sort(edge+1,edge+num+1,cmp);for (int i=1; i<=n; i++) fa[i]=i;for (int i=1; i<=num; i++){int u=edge[i].u,v=edge[i].v;if (!vis[u] || !vis[v]) continue;int f1=find(u),f2=find(v);if (f1!=f2)unionn(f1,f2),ans2+=edge[i].k;} }int main(){n=in(),m=in();for (int i=1; i<=n; i++) h[i]=in();for (int i=1; i<=m; i++){int u=in(),v=in(); LL k=Lin();if (h[u]>=h[v]) add(u,v,k);if (h[v]>=h[u]) add(v,u,k);}bfs(); kruskal();printf("%d %lld\n",ans1,ans2);return 0; }總結(jié)
以上是生活随笔為你收集整理的【最小树形图(奇怪的kruskal)】【SCOI 2012】【bzoj 2753】滑雪与时间胶囊的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Btrfs入门(一)
- 下一篇: ortp库使用入门