縮點【洛谷P1262】 間諜網絡
阿新 • • 發佈:2018-10-21
ios top 問題 ems tchar ++ 技術分享 是否 string
【洛谷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; }
縮點【洛谷P1262】 間諜網絡