codeforces 427C tarjan模板题

题意:

给你n个点每个点修建警察局的cost

对于这张图来说,与警察局在同一强联通分量里的每个点都可以被这个警察局照看  问你最小cost以及当前cost的方案数

思路:

tarjan模板题~~~ (特别鸣谢磊哥哥的倾情授课ლ(°◕‵ƹ′◕ლ))

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>

using namespace std;
const int MaxN = 1e5 + 5;
typedef long long LL;
const LL mod = 1e9 + 7;

int w[MaxN],stack[MaxN],dfn[MaxN],low[MaxN],col[MaxN];
int n,m,cnt = 0,Top = 0,haha = 0;
bool vis[MaxN];
vector<int> G[MaxN],E[MaxN];

void tarjan(int u){
	dfn[u] = ++cnt;
	low[u] = dfn[u];
	stack[++Top] = u;
	vis[u] = 1;//在stack里
	int len = G[u].size();
	for(int i = 0;i < len; i++){
		int v = G[u][i];
		if(!dfn[v]){//没访问过
			tarjan(v);
			low[u] = min(low[u],low[v]);
		}
		else if(vis[v]){//访问过 && 在栈里
			low[u] = min(low[u],dfn[v]);
		}
	}
	if(low[u] == dfn[u]){
		haha++;
		while(1){
			int cur = stack[Top];
			vis[cur] = 0;
			Top--;
			col[cur] = haha;
			if(cur == u) break;
		}
	}
}

int main()
{
	scanf("%d",&n);
	for(int i = 1;i <= n; i++) scanf("%d",&w[i]);
	scanf("%d",&m);
	for(int i = 1;i <= m; i++){
		int u,v;
		scanf("%d %d",&u,&v);
		G[u].push_back(v);
	}
	for(int i = 1;i <= n; i++){
		if(!dfn[i]) tarjan(i);
	}//搜索所有强联通分量
	for(int i = 1;i <= n; i++){
		if(!E[col[i]].size()) E[col[i]].push_back(i);
		else if(w[i] < w[E[col[i]][0]]){
			E[col[i]].clear();
			E[col[i]].push_back(i);
		}
		else if(w[i] == w[E[col[i]][0]]){
			E[col[i]].push_back(i);
		}
	}
	LL cost = 0LL,ways = 1LL;
	for(int i = 1;i <= haha; i++){
		cost += w[E[i][0]];
		ways = (ways * (LL)E[i].size()) % mod;
	}
	printf("%lld %lld\n",cost,ways);
	return 0;
}
发布了31 篇原创文章 · 获赞 5 · 访问量 1358

猜你喜欢

转载自blog.csdn.net/qq_43685900/article/details/104026231
今日推荐