日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

牛客网【每日一题】5月1日题目 [SCOI2012]滑雪与时间胶囊

發布時間:2023/12/3 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 牛客网【每日一题】5月1日题目 [SCOI2012]滑雪与时间胶囊 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

鏈接:

時間限制:C/C++ 2秒,其他語言4秒 空間限制:C/C++ 262144K,其他語言524288K 64bit IO Format: %lld

題目描述

a180285非常喜歡滑雪。他來到一座雪山,這里分布著M條供滑行的軌道和N個軌道之間的交點(同時也是景點),而且每個景點都有一編號i(1 ≤
i ≤ N)和一高度Hi。a180285 能從景點i 滑到景點j 當且僅當存在一條i 和j 之間的邊,且i 的高度不小于j。
與其他滑雪愛好者不同,a180285喜歡用最短的滑行路徑去訪問盡量多的景點。如果僅僅訪問一條路徑上的景點,他會覺得數量太少。于是a180285拿出了他隨身攜帶的時間膠囊。
這是一種很神奇的藥物,吃下之后可以立即回到上個經過的景點(不用移動也不被認為是 a180285 滑行的距離)。
請注意,這種神奇的藥物是可以連續食用的,即能夠回到較長時間 之前到過的景點(比如上上個經過的景點和上上上個經過的景點)。
現在,a180285站在1號景點望著山下的目標,心潮澎湃。他十分想知道在不考慮時間
膠囊消耗的情況下,以最短滑行距離滑到盡量多的景點的方案(即滿足經過景點數最大的前 提下使得滑行總距離最小)。你能幫他求出最短距離和景點數嗎?

輸入描述:

輸入的第一行是兩個整數N,M。 接下來1行有N個整數Hi,分別表示每個景點的高度。
接下來M行,表示各個景點之間軌道分布的情況。每行3個整數,Ui,Vi,Ki。表示編號為Ui的景點和編號為Vi的景點之間有一條長度為Ki的軌道。

輸出描述:

輸出一行,表示a180285最多能到達多少個景點,以及此時最短的滑行距離總和。

示例1
輸入

3 3 3 2 1 1 2 1 2 3 1 1 3 10

輸出

3 2

題解:

題目中說有了時間膠囊回到之前點,而且可以練習使用。我們再根據樣例畫出圖形,其實就是最小生成樹,但是邊為有向邊(也就是只能從高的地方滑向低的地方,如果一樣高可以互相達到)

完美用最小生成樹的方法來求
(之前剛寫了一個最小生成樹的文章鏈接)
最小生成樹的原理:
Kruskal:把最短的集合合并成一個集合
Prim:每次找與現有生成樹相連的最短的邊
在本題中,我們要找一個邊從a到b,可以用Kruskal的方法對點的高低進行排序(從大到小),如果兩個點高度相同則對邊進行進行排序,然后自高到低一次加入到最小生成樹的圖中。這樣就能保證所有點都是從高到低的方向走。
用Prim的話:點從高到低依次加入,然后每次加入與已有樹距離最小的樹外點,并不斷更新最短距離,這樣能保證不重不漏

據說最小樹形圖還有個專門的算法“朱-劉Edmonds算法”,恕我孤陋寡聞,等學會后更新上

代碼:

#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=100001;int n,m,head[maxn]; bool vis[maxn]; int q[maxn*20],sum1; int fa[maxn],h[maxn];struct edge{ll u,v,w,h,next; }a[maxn*20];; bool cmp(edge a,edge b) {if(a.h==b.h) return a.w<b.w;return a.h>b.h; } int tot=0; void add(int u,int v,int w) {a[++tot].next=head[u];a[tot].u=u;a[tot].v=v;a[tot].w=w;a[tot].h=h[v];head[u]=tot; } int find(ll x) {if(fa[x]==x)return x;else fa[x]=find(fa[x]); } void bfs(int now) {int end=1;sum1=1;//能經過多少點 (景點數量) q[now]=1;vis[now]=1;for(int i=1;i<=end;i++){int now=q[i];for(int j=head[now];j;j=a[j].next){if(!vis[a[j].v]){vis[a[j].v]=true;sum1++;q[++end]=a[j].v;}}} } ll kruskal() {ll sum2=0;// 最短的滑行距離總和int tot1=0;//統計目前樹中邊的數量 sort(a+1,a+1+tot,cmp);for(int i=1;i<=n;i++) fa[i]=i;for(int i=1;i<=tot;i++){if(!(vis[a[i].u] && vis[a[i].v])) continue; int f1=find(fa[a[i].u]);int f2=find(fa[a[i].v]);if(f1!=f2){fa[f2]=f1;tot1++;sum2+=a[i].w;}if(tot1==sum1-1) break;//當組成樹即完成任務 }return sum2; } int main() {int u,v,w;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)scanf("%d",&h[i]);for(int i=1;i<=m;i++){cin>>u>>v>>w;if(h[u]>=h[v]) add(u,v,w);if(h[u]<=h[v]) add(v,u,w);}bfs(1);//從1開始出發 ,看看最多能到多少景點 kruskal();cout<<sum1<<" "<<kruskal()<<endl;return 0; }

總結

以上是生活随笔為你收集整理的牛客网【每日一题】5月1日题目 [SCOI2012]滑雪与时间胶囊的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。