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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

51Nod-1299-监狱逃离

發布時間:2023/12/8 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 51Nod-1299-监狱逃离 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

ACM模版

描述

題解

先吐槽一下,我只想說,搞 ACM 的人語文表達能力真的很有限,說得云里霧里的……一開始有思路,瞄了一眼討論區,思路徹底被搞蒙了,這表達能力堪憂啊~~~抑或是我的語文理解能力低下?

這個題能夠用最小割解,十分不錯,反正我不會,也就點點贊~~~

我用的是樹歸,因為很明顯是 dp,又是樹,所以就是樹歸嘍~~~建圖,不多說,保存一下每個點的度,根據度,判斷 ?1,然后隨便找一個度為 1 的點,作為根,進行樹歸。

這里,我們需要從葉子開始往根查找,也就是說需要從底往上進行規劃,此時,我們需要考慮的是每一個點作為子樹的根時,它的兒子的情況。而他的兒子的情況大致分為三種,
0:他的這個兒子不能通往葉子,并且沒有犯人可以到達他的這個兒子,也就是說從這棵子樹的根和這個兒子之間的一切聯系都是無所謂的了;
1:他的這個兒子可以通往葉子,也就是說從這棵子樹的根可以到達葉子,這種情況我們可以肯定的是,這些路徑中肯定不會有犯人(因為從兒子能通往的葉子可能不唯一),因為如果有的話,我們肯定會在更深一層的遞歸中堵住這條路;
2:他的這個兒子不能通往葉子,但是有犯人可以到達這個兒子,此時,我們就需要格外關注這種情況了。

通過 state[] 對上述三種情況的兒子進行計數后,我們可以結合起來分析根了。
第一種,如果根就是犯人的位置,那么很不幸,我們需要把所有的第 1 類兒子進行封殺,也就是說需要 ans += state[1],此時,不管其他兒子啥情況,這個子樹的根都是第 2 類情況;
第二種,既存在第 1 類兒子,又存在第 2 類兒子,那么,第 2 類兒子中的犯人可以通過根節點到達能夠通往葉子結點的兒子那里,所以此時最佳操作不是封殺所有第 2 類兒子,而是直接封殺根,那么需要 ans++,此時根變為第 0 類情況;
第三種,如果有第 1 類或者第 2 類兒子,那么根也是同樣的情況,如果只有第 0 類兒子,那么根也是同樣的情況,注意判斷的優先級,前兩類可以不分前后,但是第 0 類的要最后判斷,自己想想為什么,很容易想的,如果三類兒子都沒有,那么說明他就是葉子,此時,我們應該注意到,所有葉子(出口)結點或者所有結點的狀態都應該初始化為可以通往出口了~~~

這個題思路不難,但是需要理清晰,不然很容易弄錯情況的~~~一開始我就是被打亂了思路,苦惱( ̄o ̄) . z Z

代碼

#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector>using namespace std;const int MAXN = 1e5 + 5;int n, m; int ans; int cnt = 0; int dg[MAXN]; // 度 int flag[MAXN]; int prisoner[MAXN]; // 犯人 vector<int> vi[MAXN];void dfs(int x, int pre) {int state[3]; // 三種狀態memset(state, 0, sizeof(state));for (int i = 0; i < vi[x].size(); i++){if (vi[x][i] != pre){dfs(vi[x][i], x);state[flag[vi[x][i]]]++;}}if (prisoner[x]) // x 點有逃犯{ans += state[1];// 加上所有能到達的葉子(出口)的兒子結點數flag[x] = 2; // x 變為不能通向葉子(出口)的兒子結點}else if (state[1] && state[2]) // 有葉子(出口)可以通到 x 并且有其他犯人可以到達 x{ans++; // x 處放置警察flag[x] = 0; // 不能到達 x}else if (state[1]) // x 是否可以通往葉子(出口){flag[x] = 1; // x 變為可以通往出口}else if (state[2]) // 是有犯人可以到達 x{flag[x] = 2; // x 變為有犯人到達}else if (state[0]) // 不能到達葉子(出口){flag[x] = 0; // x 不能通往葉子(出口)} }// 初始化所有結點都可以通往出口 void init() {for (int i = 0; i < MAXN; i++){flag[i] = 1;} }int main() {init();cin >> n >> m;n++;int x, y;for (int i = 1; i < n; i++){scanf("%d%d", &x, &y);vi[x].push_back(y);vi[y].push_back(x);dg[x]++;dg[y]++;}for (int i = 1; i <= m; i++){scanf("%d", &x);if (dg[x] == 1){printf("-1\n");return 0;}prisoner[x] = 1;}for (int i = 0; i < n; i++){if (dg[i] == 1){dfs(i, 0);if (flag[i] == 2) // 有犯人能到達根節點{ans++;}break;}}printf("%d\n", ans);return 0; }

總結

以上是生活随笔為你收集整理的51Nod-1299-监狱逃离的全部內容,希望文章能夠幫你解決所遇到的問題。

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