1. 程式人生 > >P1262 間諜網絡

P1262 間諜網絡

esp style amp clu ++ != 第一個 font ios

傳送門

顯然可以把所有間諜的關系建一個圖

如果A間諜手中掌握著關於B間諜的犯罪證據,那就從A連一條邊到B

如果賄賂了一個間諜,那麽整個聯通塊的間諜肯定都被控制

那就先把圖縮成DAG

如果控制了一個塊,那麽這個塊後面所有的塊都能被控制

為了控制所有塊,一定要賄賂沒有入度的塊,因為它不能被其它塊控制到

那就Tarjan然後賄賂所有入度為0的塊,答案就是總花費

要註意判斷是否能控制所有塊

如果一個塊不能被賄賂,並且沒有塊可以控制它,那麽它就不能被控制

那麽我們縮點的時候可以只從能被賄賂的間諜開始縮

全部縮完後如果有間諜不處於任何聯通塊,那麽ta就不能被控制

for一遍就好了

至於控制一個塊的花費就是最便宜的那個間諜,Tarjan時可以一起處理

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<0||ch>9)
    {
        
if(ch==-) f=-1; ch=getchar(); } while(ch>=0&&ch<=9) { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=3007,M=2e5+7; int n,m,t; int val[N]; int fir[N],from[M],to[M],cnt; inline void add(int &a,int
&b) { from[++cnt]=fir[a]; fir[a]=cnt; to[cnt]=b; } //Tarjan模板 int dfn[N],low[N],be[N],st[M],cnt2,_top,dfn_clock,miv[N];//miv[i]是塊i的最小費用 void Tarjan(int x) { dfn[x]=low[x]=++dfn_clock; st[++_top]=x; for(int i=fir[x];i;i=from[i]) { int &v=to[i]; if(!dfn[v]) Tarjan(v),low[x]=min(low[x],low[v]); else if(!be[v]) low[x]=min(low[x],dfn[v]); } if(low[x]==dfn[x]) { cnt2++; while(st[_top]!=x) { miv[cnt2]=min(miv[cnt2],val[st[_top]]); be[st[_top--]]=cnt2; } miv[cnt2]=min(miv[cnt2],val[st[_top]]); be[st[_top--]]=cnt2; } } int du[N]; int main() { memset(val,0x7f,sizeof(val)); memset(miv,0x7f,sizeof(miv));//初始都不能賄賂 int a,b; cin>>n>>m; for(int i=1;i<=m;i++) { a=read(); b=read(); val[a]=b; } cin>>t; for(int i=1;i<=t;i++) { a=read(); b=read(); add(a,b); } for(int i=1;i<=n;i++) if(!dfn[i]&&val[i]!=val[0]) Tarjan(i);//只從能被賄賂的間諜開始縮點 for(int i=1;i<=n;i++) if(!be[i]) { printf("NO\n%d",i);//找到的第一個間諜就是編號最小的間諜 return 0; } printf("YES\n"); for(int i=1;i<=n;i++) for(int j=fir[i];j;j=from[j]) if(be[i]!=be[to[j]]) du[be[to[j]]]++;//算一波入度 int ans=0; for(int i=1;i<=cnt2;i++) if(!du[i]) ans+=miv[i];//所有入度為0的塊都要賄賂 printf("%d",ans); return 0; }

P1262 間諜網絡