Luogu P1262 间谍网络 【强连通分量/缩点】By cellur925
生活随笔
收集整理的這篇文章主要介紹了
Luogu P1262 间谍网络 【强连通分量/缩点】By cellur925
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目傳送門
真是一道好題呀~~~~qwq
知道這題是tarjan,但是想了很久怎么用上強連通分量。因為樣例們...它顯然并不是一個強聯通分量!
(被樣例迷惑的最好例子)
然后...就沒有然后了...感覺自己被欺騙了。腦補了一些別的做法,向題解低頭。
?
?
$Sol$
這個時候我們其實需要一些冷靜分析。分情況討論。
- 判斷無解性。什么時候無解?當存在一個間諜既不能被收買也沒有被其他間諜掌握自己的資料,則無解。我們在主函數進行tarjan操作時,是從能被收買的間諜開始找環的。那么最后遞歸結束,當存在間諜沒被訪問($!dfn[i]$),那么問題無解。
- 那么有解的情況呢?這時條件等價于所有的間諜都能直接或間接地被收買或被掌握。這時分兩種情況:正如我思考時,分有環和無環兩種情況。沒還,資金就需要給那個沒有入度的間諜;有環,我們就把資金給那個在環里資金最小的間諜(因為在一個強聯通分量中,所以一個點可達另一個節點,這個環就解決了,我們肯定想要給資金需要少的。這部分處理可在tarjan中順便求出)。有環的情況我們通常對它進行縮點,成為一個有向無環圖,也就變成了無環的情況。
- 小結。縮點->DAG這是比較套路的東西了,大多數時候我們其實不用新建一個圖,而都是在統計入度(這種場合較多)。
- 結論。還是我太弱了qwq。
?
$Code$
1 #include<cstdio> 2 #include<algorithm> 3 #include<stack> 4 #include<cstring> 5 #define maxn 4000 6 7 using namespace std; 8 9 int n,p,tot,r,dfs_clock,scc_cnt,ans; 10 int head[maxn],val[maxn],rdu[maxn],dfn[maxn],low[maxn],scc[maxn],price[maxn]; 11 bool buy[maxn]; 12 struct node{ 13 int to,next; 14 }edge[maxn*2]; 15 stack<int>s; 16 17 void add(int x,int y) 18 { 19 edge[++tot].to=y; 20 edge[tot].next=head[x]; 21 head[x]=tot; 22 } 23 24 void tarjan(int u) 25 { 26 dfn[u]=low[u]=++dfs_clock; 27 s.push(u); 28 for(int i=head[u];i;i=edge[i].next) 29 { 30 int v=edge[i].to; 31 if(!dfn[v]) 32 { 33 tarjan(v); 34 low[u]=min(low[u],low[v]); 35 } 36 else if(!scc[v]) low[u]=min(low[u],dfn[v]); 37 } 38 if(dfn[u]==low[u]) 39 { 40 scc_cnt++; 41 while(1) 42 { 43 int x=s.top();s.pop(); 44 scc[x]=scc_cnt; 45 val[scc_cnt]=min(val[scc_cnt],price[x]); 46 if(x==u) break; 47 } 48 } 49 } 50 51 int main() 52 { 53 scanf("%d%d",&n,&p); 54 memset(price,127,sizeof(price)); 55 memset(val,127,sizeof(val)); 56 for(int i=1;i<=p;i++) 57 { 58 int x=0; 59 scanf("%d",&x); 60 buy[x]=1; 61 scanf("%d",&price[x]); 62 } 63 scanf("%d",&r); 64 for(int i=1;i<=r;i++) 65 { 66 int x=0,y=0; 67 scanf("%d%d",&x,&y); 68 add(x,y); 69 } 70 for(int i=1;i<=n;i++) 71 if(!dfn[i]&&buy[i]) tarjan(i); 72 for(int i=1;i<=n;i++) 73 if(!dfn[i]){ans=i;break;} 74 if(ans) {printf("NO\n%d",ans);return 0;} 75 printf("YES\n"); 76 for(int x=1;x<=n;x++) 77 for(int i=head[x];i;i=edge[i].next) 78 { 79 int y=edge[i].to; 80 if(scc[x]==scc[y]) continue; 81 rdu[scc[y]]++; 82 } 83 for(int i=1;i<=scc_cnt;i++) 84 if(rdu[i]==0) ans+=val[i]; 85 printf("%d",ans); 86 return 0; 87 } View Code$Warning$
那個最后縮點的時候這個地方比較容易寫錯。最后是在$scc_cnt$上進行操作的。
for(int x=1;x<=n;x++)for(int i=head[x];i;i=edge[i].next){int y=edge[i].to;if(scc[x]==scc[y]) continue;rdu[scc[y]]++;}for(int i=1;i<=scc_cnt;i++)if(rdu[i]==0) ans+=val[i];?
轉載于:https://www.cnblogs.com/nopartyfoucaodong/p/9733577.html
總結
以上是生活随笔為你收集整理的Luogu P1262 间谍网络 【强连通分量/缩点】By cellur925的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PyQt5-关闭窗体显示提示框(窗口界面
- 下一篇: 六、jQuery基础