缩点【洛谷P1262】 间谍网络
【洛谷P1262】 間諜網絡
題目描述
由于外國間諜的大量滲入,國家安全正處于高度的危機之中。如果A間諜手中掌握著關于B間諜的犯罪證據,則稱A可以揭發B。有些間諜收受賄賂,只要給他們一定數量的美元,他們就愿意交出手中掌握的全部情報。所以,如果我們能夠收買一些間諜的話,我們就可能控制間諜網中的每一分子。因為一旦我們逮捕了一個間諜,他手中掌握的情報都將歸我們所有,這樣就有可能逮捕新的間諜,掌握新的情報。
我們的反間諜機關提供了一份資料,包括所有已知的受賄的間諜,以及他們愿意收受的具體數額。同時我們還知道哪些間諜手中具體掌握了哪些間諜的資料。假設總共有n個間諜(n不超過3000),每個間諜分別用1到3000的整數來標識。
請根據這份資料,判斷我們是否有可能控制全部的間諜,如果可以,求出我們所需要支付的最少資金。否則,輸出不能被控制的一個間諜。
一個環內的點當做一個點,進行有向圖縮點,縮點之后的點權就是該點包括的點的點權最小值。
之后重新建圖,對于每個點如果他的點權不是無限大,那么就可以從他開始擴展,dfn就可以解決。不過有一點問題,就是如果可以遍歷所有點,那么我們是需要輸出最小代價的。
那么嘗試hack一下現在的做法。
可以發現,確實會有地方多計算了點權。
比如下面這個圖。
按照當前做法,1號點的點權10也會被計算到答案里,但是我們只需要5號點的點權20就可以了。
所以就有了一個優化,就是統計重新建圖之后每個點的入度,然后從入度為零的點開始遍歷。
之后再去從入度不為零的點遍歷。
code:
#include <iostream> #include <cstdio> #include <cstring>using namespace std;const int wx=50017;inline int read(){int sum=0,f=1; char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar();}return sum*f; }int tot,st[wx],top,col,n,p,m; int head[wx],h[wx],num,Num; int dfn[wx],low[wx],belong[wx],size[wx],a[wx],v[wx],vis[wx]; int in[wx];struct e{int nxt,to; }edge[wx*2];void add(int from,int to){edge[++num].nxt=head[from];edge[num].to=to;head[from]=num; }void Tarjan(int u){dfn[u]=low[u]=++tot;st[++top]=u;for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].to;if(!dfn[v]){Tarjan(v);low[u]=min(low[u],low[v]);}else if(!belong[v]){low[u]=min(low[u],dfn[v]);}}if(low[u]==dfn[u]){belong[u]=++col;size[col]++;while(st[top]!=u){belong[st[top]]=col;size[col]++;top--;}top--;} }struct node{int nxt,to; }e[wx*2];void Add(int from,int to){e[++Num].nxt=h[from];e[Num].to=to;h[from]=Num; }void dfs(int u){vis[u]=1;for(int i=h[u];i;i=e[i].nxt){int v=e[i].to;if(vis[v])continue;dfs(v);} }int main(){n=read(); p=read();memset(a,0x3f,sizeof a);memset(v,0x3f,sizeof v);for(int i=1;i<=p;i++){int x; x=read(); a[x]=read();}m=read();for(int i=1;i<=m;i++){int x,y;x=read(); y=read();add(x,y);}for(int i=1;i<=n;i++)if(!dfn[i])Tarjan(i);for(int i=1;i<=n;i++)v[belong[i]]=min(v[belong[i]],a[i]);for(int u=1;u<=n;u++){for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].to;if(belong[v]!=belong[u])in[belong[v]]++,Add(belong[u],belong[v]);}}int ans=0;for(int i=1;i<=col;i++){if(v[i]!=0x3f3f3f3f&&vis[i]==0&&in[i]==0){if(i==1)vis[i]=1;ans+=v[i];dfs(i);}}for(int i=1;i<=col;i++){if(v[i]!=0x3f3f3f3f&&vis[i]==0){if(i==1)vis[i]=1;ans+=v[i];dfs(i);}}for(int i=1;i<=n;i++){if(!vis[belong[i]]){puts("NO");printf("%d\n",i); return 0;}}puts("YES");printf("%d\n",ans);return 0; }轉載于:https://www.cnblogs.com/wangxiaodai/p/9826762.html
總結
以上是生活随笔為你收集整理的缩点【洛谷P1262】 间谍网络的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jpa-spring -basic
- 下一篇: 取小数的常见操作