洛谷P5008 逛庭院 tarjan縮點 貪心

2022-08-18 06:12:13 字數 3242 閱讀 1472

--

首先我們看到資料範圍。媽耶!資料這麼大,一開始還想用個dp來做,但是看著就不行,那麼根據這個資料範圍,我們大致可以猜到這道題的演算法是乙個貪心,那麼我們怎麼貪呢?

我們首先還是先畫乙個圖:

樣例解釋一下:

我們取的點是\(3\),\(5\),\(7\)。

看到題目,因為\(1\)號節點的入度為0,那麼就一定不能選擇\(1\)號節點,那麼接下來可以供我們選擇的最大的權值的點也就只有\(3\),\(5\),\(7\)號節點,那麼我們就來乙個貪心策略:對每乙個節點的權值進行排序,然後將所有不能取的節點全部不算,剩下的就都取最大的那幾個。

以下是\(30\)分騙分程式

# include # define ri register int

# define for1(i,a,b) for(ri i(a);i<=b;++i)

# define for2(i,a,b) for(ri i(a);i>=b;--i)

using namespace std;

inline int read ()

while (isdigit(ch))

return w ? -x : x;

}const int maxm = 2000004;

const int maxn = 5000004;

int nedge, n, m, k;

int head[maxm], ind[maxn];

struct nodea[5000004];

bool cmp (node a,node b)

int main()

sort (a + 1 , a + 1 + n , cmp);

int cnt = 0 , ans = 0;

for1(i ,1 ,n)

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

return 0;

}

但是這個貪心一定是錯的。

我們來想一下,如果可以去掉的節點,是某乙個接下來可以取的節點的唯一乙個入邊**,那麼這個一定會影響後面的答案,這個點也就不取了,所以我們就不能這樣做。

那麼我們應該怎麼做呢?

這個時候我們就需要膽大心細地思考題目了。我是好好聽了出征大會的

其實也就只需要在這個貪心的基礎上,加上乙個契機,這個契機就是讓當前這個刪去的點,可以不對後面的點產生影響。

正解策略是:我們首先縮點,然後找到入度為0的環,刪去這個環中權值最小的點,然後從小到大排序,取前k大的點。

我們先給乙個縮點的模板吧!

inline void tarjan(int u) 

else if (vis[v]) low[u] = min(low[u] ,low[v]);

}int j;

if (dfn[u] == low[u])

while (u != j) ;}}

那麼我們就需要乙個手段,使得這個這個點成為乙個刪去和不刪去,不會影響答案得到東西:這個玩意的名字叫做縮點。

為什麼我們會想到縮點,我們得從dag中的環開始說起。

早在。。因為在有向圖中,每乙個點都是可以互相到達的,那麼所以這個有向圖中的每乙個點都是有入度的,沒有人反駁吧!,所以這個裡面的點都是可以隨意取的,但是要注意attention:當你這這個環是\(0\)的入度時,那麼你就不能隨意取掉最後乙個點了,因為你這個最後乙個點可能就沒有入度了,那麼我們為了保證所有的點都可以取到,我們就將這個環內的權值最小的點刪去,那麼這樣就可以保證這個環斷開後,這個點集中的點就可以隨便取了。

其實也是乙個道理,我就不解釋了,也就是把這個點刪掉,反正這個點完全沒有用。

以下是ac**(新的碼風本人感覺還是挺好看的qaq)

# include # define ri register int

# define for1(i,a,b) for(ri i(a);i<=b;++i)

# define for2(i,a,b) for(ri i(a);i>=b;--i)

# define ms(a,b) memset(a,b,sizeof(a))

using namespace std;

typedef long long ll;

const int m = 2000005;

struct edgeedge[m];

int dfn[m], vis[m], low[m], s[m], head[m] ,belong[m] ,ind[m];

int dep, top, sum , n ,m ,k ,nedge;

struct nodea[m];

inline int read() //快讀

while (isdigit(ch))

return w ? -x : x ;

}inline int min(int n,int m) //三目取min

inline void add_edge(int u ,int v) //鏈式前向星

; head[u] = nedge++;

}inline void tarjan(int u) //tarjan縮點模板

else if (vis[v]) low[u] = min(low[u] ,low[v]);

}int j;

if (dfn[u] == low[u])

while (u != j) ;

}}inline bool cmp1(node a,node b) //從小到大排序

inline bool cmp2(node a,node b) //從大到小排序

int main()

for1(i ,1 ,n)

for1(i ,1 ,n)

}//統計當前縮完點後的每個點的入度

sort(a + 1, a + 1 + n ,cmp1);

for1(i ,1 ,n)

}//刪去乙個聯通塊中權值最小的點

sort(a + 1 , a + 1 + n ,cmp2);

ll ans = 0, cnt = 0;

for1(i ,1 ,n) //計算我們的答案

printf ("%lld\n", ans);

return 0;

}

洛谷5008 逛庭院(Tarjan,貪心)

洛谷 如果圖是乙個 dag 我們可以任意選擇若干個不是入度為 0 的點,然後把它們按照拓撲序倒序刪掉,不難證明這樣一定是合法的。現在的問題是出現了 scc 我們縮點之後 scc 形成了乙個 scc 我們還是貪心考慮,顯然不是入度為 0 的 scc 仍然可以類似上面的任意刪點,只需要按照 scc 的拓...

luogu5008 逛庭院 tarjan縮點

首先如果這是乙個dag,我按照拓撲序倒著去選,一定能選到所有入度不為0的點 然後考慮有環的情況 我們拎出來乙個強連通分量 先假設它縮點以後是沒有入度的 那我最後它裡面一定至少剩乙個不能選 因為就剩乙個的時候肯定沒有入度呀 那我顯然可以把它看成是乙個只有乙個點入度為0的dag 而且那個入度為0的點可以...

Tarjan縮點 洛谷P2341

傳送門 這題很簡單,不知道為什麼是提高組的題.主要思路就是先tarjan縮點,然後在dag上找出度為0的點,如果只有乙個出度為0的點,那麼這個點就是的大小就是受歡迎的牛的數目。如果有兩個及以上個點的出度為0,那麼不存在明星牛。下面是 include using namespace std const...