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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

【luogu P5022 旅行】 题解

發(fā)布時間:2023/12/20 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【luogu P5022 旅行】 题解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

題目連接:https://www.luogu.org/problemnew/show/P5022

\(NOIP2018 DAY2T1\)

考場上只寫了60分,很容易想到當 m = n - 1 時的樹的做法。

讀題推一下樣例不難發(fā)現(xiàn),如果選擇一個分支節(jié)點就必須走到頭——直到一個節(jié)點沒有子樹。

那么我們就可以貪心的求得最小字典序序列,每次選擇節(jié)點編號最小的走。

即對當前節(jié)點的所有子節(jié)點排序選擇最小編號的往下進行即可。

60分code:

#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 5010; struct edge{int to, next; }e[maxn<<2]; int head[maxn], cnt, n, m; bool vis[maxn]; void add(int u, int v) {e[++cnt].to = v; e[cnt].next = head[u]; head[u] = cnt; } void dfs(int x) {if(vis[x]) return;vis[x] = 1;printf("%d ",x);int a[maxn], num = 0;for(int i = 1; i <= n; i++) a[i] = 0;for(int i = head[x]; i != -1; i = e[i].next)a[++num] = e[i].to;sort(a+1, a+1+num);for(int i = 1; i <= num; i++)dfs(a[i]); } int main() {memset(head, -1, sizeof(head));scanf("%d%d",&n,&m);for(int i = 1; i <= m; i++){int u, v;scanf("%d%d",&u,&v);add(u, v);add(v, u);}dfs(1);return 0; }

100分做法:

考慮 m = n 這個情況,樹多加一條邊(無自環(huán)重邊情況下)會變成一個環(huán)套樹。

環(huán)套樹有一個性質(zhì)是刪去環(huán)上的一邊就會成為一棵樹。

那么當是一棵樹的時候,我們能找到一個最優(yōu)解,當 m = n 時,我們就可以找出多棵樹的最優(yōu)解,在這些最優(yōu)解中選取一個最優(yōu)的最優(yōu)解,就是 m = n 時的最優(yōu)解。

所以我們只需要把這多棵樹的最優(yōu)解找出來就行了。

所以我們需要把環(huán)上的邊枚舉斷掉使原圖成為一棵樹再進行60分的做法。

考慮數(shù)據(jù)范圍<=5000,N^2暴力斷邊即可。

code:

#include <vector> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 5010; struct edge{int to, next; }e[maxn<<2]; int head[maxn], cnt, n, m, u[maxn], v[maxn]; bool vis[maxn]; void add(int u, int v) {e[++cnt].to = v; e[cnt].next = head[u]; head[u] = cnt; } void dfs(int x) {if(vis[x]) return;vis[x] = 1;printf("%d ",x);int a[maxn], num = 0;for(int i = 1; i <= n; i++) a[i] = 0;for(int i = head[x]; i != -1; i = e[i].next)a[++num] = e[i].to;sort(a+1, a+1+num);for(int i = 1; i <= num; i++)dfs(a[i]); } //======================= vector<int> E[maxn]; int ANS[maxn], NOW[maxn], TOT, CUTu, CUTv; bool VIS[maxn]; void DFS(int x) {if(VIS[x]) return;VIS[x] = 1;NOW[++TOT] = x;for(int i = 0; i < E[x].size(); i++){int y = E[x][i];if((y == CUTv && x == CUTu) || (x == CUTv && y == CUTu)) continue;DFS(y);} } bool check() {for(int i = 1; i <= n; i++){if(ANS[i] == NOW[i]) continue;if(ANS[i] > NOW[i]) return 1;if(ANS[i] < NOW[i]) return 0;} } int main() {memset(head, -1, sizeof(head));scanf("%d%d",&n,&m);for(int i = 1; i <= m; i++){scanf("%d%d",&u[i],&v[i]);add(u[i], v[i]);add(v[i], u[i]);E[u[i]].push_back(v[i]);E[v[i]].push_back(u[i]);}for(int i = 1; i <= n; i++) sort(E[i].begin(), E[i].end());if(m == n-1){dfs(1);return 0;}else{for(int i = 1; i <= m; i++){TOT = 0, CUTu = u[i], CUTv = v[i];memset(VIS, 0, sizeof(VIS));DFS(1);if(TOT == n){if(ANS[1] == 0){for(int j = 1; j <= n; j++)ANS[j] = NOW[j];}else if(check()){for(int j = 1; j <= n; j++)ANS[j] = NOW[j];}}}for(int i = 1; i <= n; i++)printf("%d ",ANS[i]);return 0;} }

后記:

半退役選手回來的第二篇題解。

想想去年自己距離省一線差了10分,即使過去半年心里也依舊不是滋味。

DAY2考時想不起環(huán)套樹來,考后出考場的一剎那就想到了可以N^2暴力斷邊。

其實環(huán)套樹考前是講過的,斷邊操作也是老師提到過的。

可是自己卻總覺得環(huán)套樹在NOIP比較冷門吧也沒怎么去鞏固練習。

可事后再去后悔再去抱怨終究是一點用都沒有的。

轉(zhuǎn)載于:https://www.cnblogs.com/MisakaAzusa/p/11002522.html

總結(jié)

以上是生活随笔為你收集整理的【luogu P5022 旅行】 题解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。