Luogu1262 间谍网络 - 缩点 - 贪心 -

题目链接:https://www.luogu.com.cn/problem/P1262

题解:
NO的情况显然就是所有收买的间谍dfs之后仍有未访问的人
显然如果一个间谍在某个强连通分量里面,就可以进而控制所有这个强连通分量里的间谍
所以tarjan缩点之后对所有入度为0的点对应的间谍出价最小的加起来即可

代码:

// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 10005;

int n,p,m, cst[maxn], de[maxn];
struct spy{int cs,to;}sp[maxn];
vector<int>g[maxn], h[maxn];
pii ed[maxn];

struct _scc{
	int dfn[maxn], low[maxn], dfs_clock;
	int stk[maxn], tp = 0, belong[maxn], tot=0, sz[maxn];
	// belong[i] i 属于哪个强连通块 tot 块数(新的n)sz 每个块的大小 
	_scc(){memset(dfn,0,sizeof dfn);}
	
	void tarjan(int x){
		dfn[x] = low[x] = ++ dfs_clock; 
		stk[++ tp] = x;
		for(int u : g[x]){
			if(!dfn[u]){
				tarjan(u);
				low[x] = min(low[x], low[u]);
			}else if(!belong[u])
				low[x] = min(low[x], dfn[u]); 
		}
		if(low[x] == dfn[x]){
			belong[x] = ++tot;
			++sz[tot];
			while(stk[tp] != x){
				++sz[tot];
				belong[stk[tp]] = tot;
				-- tp;
			}
			-- tp;
		}
	}
	
	void getscc(){
		for(int i=1;i<=n;i++)
			if(!dfn[i])tarjan(i);
	}
	
	void deal(){	// 缩点 
		for(int i=1;i<=m;i++){
			int x = ed[i].first, y = ed[i].second;
			if(belong[x] != belong[y])
				h[belong[x]].push_back(belong[y]),
				++ de[belong[y]];
		}
	}
};
struct _scc scc;

int vis[maxn];
void dfs(int x){
	vis[x] = 1;
	for(int u : g[x]){
		if(!vis[u])dfs(u);
	}
}

signed main(){
//	freopen("1262.in","r",stdin);
	memset(cst, 0x3f, sizeof cst);
	scanf("%d%d",&n,&p);
	for(int i=1;i<=p;i++)scanf("%d%d",&sp[i].to,&sp[i].cs);
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		int x,y;scanf("%d%d",&x,&y);
		g[x].push_back(y);
		ed[i] = mpr(x, y);
	}
	for(int i=1;i<=p;i++)
		dfs(sp[i].to);
	for(int i=1;i<=n;i++)
		if(!vis[i])return printf("NO\n%d\n",i), 0;
	scc.getscc();
	scc.deal();
	for(int i=1;i<=p;i++)
		cst[scc.belong[sp[i].to]] = min(cst[scc.belong[sp[i].to]], sp[i].cs); 
	int ans = 0;
	for(int i=1;i<=scc.tot;i++)
		if(!de[i])ans += cst[i];
	printf("YES\n%d\n",ans);

	return 0;
}
posted @ 2022-11-22 14:42  SkyRainWind  阅读(25)  评论(0编辑  收藏  举报