洛谷 P2835 燒錄光碟

2022-05-06 20:24:10 字數 3045 閱讀 7595

其實這題水的一批...............

在jsoi2005夏令營快要結束的時候,很多營員提出來要把整個夏令營期間的資料燒錄成一張光碟給大家,以便大家回去後繼續學習。組委會覺得這個主意不錯!可是組委會一時沒有足夠的空光碟,沒法保證每個人都能拿到燒錄上資料的光碟,又來不及去買了,怎麼辦呢?!

組委會把這個難題交給了lhc,lhc分析了一下所有營員的地域關係,發現有些營員是乙個城市的,其實他們只需要一張就可以了,因為乙個人拿到光碟後,其他人可以帶著u盤之類的東西去拷貝啊!

可是,lhc調查後發現,由於種種原因,有些營員並不是那麼的合作,他們願意某一些人到他那兒拷貝資料,當然也可能不願意讓另外一些人到他那兒拷貝資料,這與我們jsoi宣揚的團隊合作精神格格不入!!!

現在假設總共有n個營員(2<=n<=200),每個營員的編號為1~n。lhc給每個人發了一張調查表,讓每個營員填上自己願意讓哪些人到他那兒拷貝資料。當然,如果a願意把資料拷貝給b,而b又願意把資料拷貝給c,則一旦a獲得了資料,則b,c都會獲得資料。

現在,請你編寫乙個程式,根據**上來的調查表,幫助lhc計算出組委會至少要燒錄多少張光碟,才能保證所有營員回去後都能得到夏令營資料?

輸入格式:

先是乙個數n,接下來的n行,分別表示各個營員願意把自己獲得的資料拷貝給其他哪些營員。即輸入資料的第i+1行表示第i個營員願意把資料拷貝給那些營員的編號,以乙個0結束。如果乙個營員不願意拷貝資料給任何人,則相應的行只有1個0,一行中的若干數之間用乙個空格隔開。

輸出格式:

乙個正整數,表示最少要燒錄的光碟數。

輸入樣例#1:

5

2 3 4 0

4 5 000

1 0

輸出樣例#1:

1

首先,這題有兩種做法:並查集可以水過,然而太監就正解完事了啊。

所以首先說一下tarjan的做法:

我們先建個圖,然後就可以很顯然的發現:

乙個環只需要一張光碟qaq。

只有每個入度為0的點需要光碟!

那麼我們的思路就很好發現了丫,我們先縮個點,然後就可以很容易的統計一下入度為零的個數啊耶!

至此本題完結。

放上**。

#includeusing

namespace

std;

intn;

int dfn[205],low[205

];int

cnt;

bool ins[205

];int head[205],tot,s[205

],tp,k;

int inn[205],chu[205],hao[205

];bool vis[205],viss[205

];struct

edgea[

100000],b[100000

];void add(int u,int

v)void tarjan(int

x)

else

if(ins[a[i].to]==true

) low[x]=min(low[x],dfn[a[i].to]);

}if(dfn[x]==low[x]) while(x!=y);

}}int

main()

}for(int i=1;i<=n;i++)

if(!dfn[i]) tarjan(i);

for(int x=1;x<=n;x++)

for(int i=head[x];i;i=a[i].nxt)

int ans=0,ans2=0

;

for(int i=1;i<=n;i++)

if(inn[hao[i]]==0&&!vis[hao[i]])

if(k==1) cout<<1

<;

else coutreturn0;

}

二:找爸爸 並查集

很多人會發現

並查集時會將兩個點結成雙向的邊。

即本來只能a是b的爸爸,但是並查集之後b也是a的爸爸了顯然**有點問題

所以這樣就會導致最終統計的光碟數減少

其實我們只需要把並查集改一改,合併操作略有變化.改成「單向並查集」.

如果x願意把光碟分享給y,就合併x的根和y本身,可以這麼理解:x的根分享給x,x再分享給y

原版的並查集是合併x、y的根,這裡不能這麼做,因為這麼做即表示:x的根可以分享給y的根(然而並不是)

此處還用了floyd轉移關係。

特別感謝**提供者!!

#include using

namespace

std;

int g[210][210

];int

n, ans;

int f[210]; //

父親 int ufs[210]; //

結點是否為並查集的根

int find(int

x) void unite(int x, int

y)

intmain()

}for(int k=1; k<=n; k++) //

floyd

for(int i=1; i<=n; i++)

for(int j=1; j<=n; j++)

g[i][j] = g[i][j] || (g[i][k] &&g[k][j]);

for(int i=1; i<=n; i++)

for(int j=1; j<=n; j++)

if(g[i][j]) unite(i, j);

for(int i=1; i<=n; i++) ufs[find(i)] = 1

;

for(int i=1; i<=n; i++) if(ufs[i]) ans ++;

cout

<< ans

}

最後,此處鏈結一種很神奇的方法!!-->點我點我

至此完結,謝謝!

洛谷 P2835 燒錄光碟

這道題目 先把沒有入度的點去灌水一遍 然後對於剩下的每乙個圖 他們不一定是乙個環 但是一定包含乙個環 我們只要找到乙個在環上的點,那麼就可以吧整個圖都灌水 include define ll long long using namespace std const int n 205 struct c...

洛谷P2835燒錄光碟

在jsoi2005夏令營快要結束的時候,很多營員提出來要把整個夏令營期間的資料燒錄成一張光碟給大家,以便大家回去後繼續學習。組委會覺得這個主意不錯!可是組委會一時沒有足夠的空光碟,沒法保證每個人都能拿到燒錄上資料的光碟,又來不及去買了,怎麼辦呢?組委會把這個難題交給了lhc,lhc分析了一下所有營員...

P2835 燒錄光碟 (tarjan縮點)

題目描述 現在假設總共有n個營員 2 n 200 每個營員的編號為1 n。lhc給每個人發了一張調查表,讓每個營員填上自己願意讓哪些人到他那兒拷貝資料。當然,如果a願意把資料拷貝給b,而b又願意把資料拷貝給c,則一旦a獲得了資料,則b,c都會獲得資料。求最小需要燒錄多少張光碟。題目鏈結 演算法 ta...