NOIP2017模擬 轟炸 強連通分量

2021-08-10 07:46:44 字數 2010 閱讀 4647

題目大意

給你n個點m條邊的有向圖,一次可以炸毀任意多個點(炸毀後不影響邊),但前提是可到達的點不能同時炸毀,問炸毀n個點至少需要多少次?

資料範圍

對於 20%的資料,n,m<=10。

對於 40%的資料,n,m<=1000。

對於另外 30%的資料,保證無環。

對於 100%的資料,n,m<=1000000

資料範圍很大,這其實是乙個很好的提示,似乎只能承受o(

n)級別的演算法。

主要說說比賽時我的思路。

「對於另外 30%的資料,保證無環」,有環或許更難考慮(通常地說都是這樣),所以我們先考慮無環的情況。

在沒有環的情況中,最簡單的應該算一條鏈了。顯然,要刪完一條鏈的點必須乙個乙個地刪。

再考慮類似樹的情況,即乙個節點分出多條鏈。

可以看出,對於分叉點a,它和它的「子樹」中的點不能和a的「父親」及以上的點同時刪,但是各個「子樹」中的刪點是互不影響的,也就是說,可以同時進行。因此處理完a及a的「子樹」的最少花費是(1

+max

len)

也就是最長鏈長度,這裡就已經接近正解了。

所以,如果沒有環,我們可以建立乙個虛擬點,向原圖中入度為零的點各連一條權值為0的邊,那麼答案就是新圖中最長鏈的長度

再考慮有環的情況。容易想到強連通分量縮點,tarjan的時間複雜度o(

v+e)

,也恰好對得上,那就考慮處在同乙個強連通分量的點。由於可以互相到達,所以必須乙個乙個地刪完。將這個強連通分量縮成乙個權值等同於其中點數的新點即可。

tarjan時間複雜度和找最長鏈搜尋時間複雜度都是線性級別的,這樣就可以ac了。

**:

#include

#include

#include

#include

#define min(x,y) ((x#define maxn 1200005

#define maxm 1200005

using

namespace

std;

int n,m,ans;

int en[maxm],las[maxn],nex[maxm],tot;

void add(int x,int y)

stack

s;int dfn[maxn],low[maxn],be[maxn],scc,vt,size[maxn];

bool in[maxn];

void tarjan(int x)

else

if(in[y])low[x]=min(dfn[y],low[x]);

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

scc++;

dowhile(y!=x);

}int en[maxm],las[maxn],nex[maxm],tot;

void readd(int x,int y)

int deg[maxn];

int f[maxn];

int getans(int x)//找最長鏈

ans+=size[x];

return f[x]=ans;

}int main()

for(i=1;i<=n;i++)if(!dfn[i])tarjan(i);

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

for(i=1;i<=scc;i++)if(deg[i]==0)readd(scc+1,i);

memset(f,-1,sizeof(f));

ans=getans(scc+1);

printf("%d",ans);

}

NOIP2017模擬 鴨舌

題目 小美喜歡吃鴨舌。有乙個 n 個點的樹,每個節點 i 第 i 個點上有 ai 個鴨舌。小美一開始處於 x 號點。每次小美可以選擇乙個與現在的點有邊的點而且那個點還有鴨舌,那麼小美會走到那個點並吃乙個鴨舌。要保證小美最後還是走到 x 號點。問小美最多能吃幾個鴨舌?輸入格式 輸入第一行乙個整數 n ...

NOIP2017模擬 區間

2017.11.3 t1 2032 樣例資料 輸入3 2 1 2 1 1 2 4 5輸出 2 6分析 這道題為什麼要放在t1 考得我懷疑人生。本來也只會暴力找,對於30 的資料我是這樣的 先離散化,再二維陣列記錄所有顏色的在每個位置的字首和,然後四層迴圈暴力查詢。而正解是 先離散化,再把每種顏色的每...

NOIP2017模擬 舉辦比賽

2017.8.27 t1 1946 樣例資料1 輸入5 5 1 2 3 4 5 輸出 樣例資料2 輸入10000000 10000000 555 888 777 666 12345 輸出 分析 第一次做這種隨機概率題 看到資料那麼大o n 的做法根本想不到就直接放棄了。結果就是個撞運氣的ffffff...