首页 > 其他分享 >2024/2/20

2024/2/20

时间:2024-02-20 23:34:21浏览次数:25  
标签:cnt 20 int scc 2024 ++ low instk

今天学习一下缩点。

强连通的蓝题真水

luogu p2812

题意:

学校有n台计算机,他们之间有线路相连,我们视为有向边。

(1)问要使得所有计算机都能获取到一个消息,需要几台母机?

(2)如果用一台母机传播消息使得所有计算机都接收到,需要添加几条新的线路?

思路:

这个题是缩点的模板题。

首先通过tarjan的scc求得有向图中的环,每个环就相当于一个点,因为环内的每个点都可以任意到一个其他点。

简化有向图之后我们统计剩下点的入度和出度为零的点的数量,取最大值。

解释如图:

image-20240220212842523

这三个图都需要练两条边。

注意还要特判一下如果只有一个联通量第二个数字是0

具体实现看代码(妙):

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 5;

vector<int>e[N];
int dfn[N], low[N], tot;
int stk[N], instk[N], top;	// 栈的作用是记录正在访问的点
int scc[N], siz[N], cnt;	//最后的结果是scc[i] = k 记录第i个节点在第k个强连通分量里,大小是siz【k】
int in[N], out[N];

void tarjan(int x) {
	//入x时, 盖戳, 入栈
	dfn[x] = low[x] = ++tot;
	stk[++top] = x, instk[x] = 1;
	for (int y : e[x]) {
		if(!dfn[y]) {		//若y尚未访问
			tarjan(y);
			low[x] = min(low[x], low[y]);		//回x时更新low
		}
		else if(instk[y]) { //若y已访问且在栈中
			low[x] = min(low[x], low[y]);
		}
		// 剩下已经访问并且不在栈中的情况是y已经被访问完,不在枚举
	}
	//离x时,记录scc
	if(dfn[x] == low[x]) { //若x是scc的根
		int y; ++cnt;
		do{		//陆续把强连通分量出栈
			y = stk[top--]; instk[y] = 0;
			scc[y] = cnt; //scc编号
			++siz[cnt];   //scc大小
		} while(y != x);
	}
} 

void solve() {
	int n;
	cin >> n;
	
	for (int i = 1; i <= n; i++) {
		int t;
		while(cin >> t && t) {
			e[i].push_back(t);
		}
	}
	
	for (int i = 1; i <= n; i++) {
		if(!dfn[i]) {
			tarjan(i);
		}
	}

	for (int i = 1; i <= n; i++) {
		for (auto it : e[i]) {
			if(scc[i] != scc[it]) {
				in[scc[it]]++;
				out[scc[i]]++;
			}
		}
	}

	int a = 0, b = 0;
	for (int i = 1; i <= cnt; i++) {
		a += (in[i] == 0);
		b += (out[i] == 0); 
	}

	cout << a << endl;
	if(cnt == 1) {
		cout << 0 << endl;
	}
	else {
		cout << max(a, b) << endl;
	}
}

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);

	int T = 1; 
	while(T--) {
		solve();
	}

	return 0;
}

p2002

题意:

n个城市m条有向边,问从至少几个城市开始扩散消息能够把消息全部扩散。

思路:

很裸的缩点题,tarjan缩点之后统计入度为零的点就行了。

#include <bits/stdc++.h>
using namespace std;
	
const int N = 1e5 + 5;

vector<int>e[N];
int dfn[N], low[N], tot;
int stk[N], instk[N], top;	// 栈的作用是记录正在访问的点
int scc[N], siz[N], cnt;	//最后的结果是scc[i] = k 记录第i个节点在第k个强连通分量里,大小是siz【k】
int in[N], out[N];

void tarjan(int x) {
	//入x时, 盖戳, 入栈
	dfn[x] = low[x] = ++tot;
	stk[++top] = x, instk[x] = 1;
	for (int y : e[x]) {
		if(!dfn[y]) {		//若y尚未访问
			tarjan(y);
			low[x] = min(low[x], low[y]);		//回x时更新low
		}
		else if(instk[y]) { //若y已访问且在栈中
			low[x] = min(low[x], low[y]);
		}
		// 剩下已经访问并且不在栈中的情况是y已经被访问完,不在枚举
	}
	//离x时,记录scc
	if(dfn[x] == low[x]) { //若x是scc的根
		int y; ++cnt;
		do{		//陆续把强连通分量出栈
			y = stk[top--]; instk[y] = 0;
			scc[y] = cnt; //scc编号
			++siz[cnt];   //scc大小
		} while(y != x);
	}
} 

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);

	int n, m;
	cin >> n >> m;


	for (int i = 0, u, v; i < m; i++) {
		cin >> u >> v;
		e[u].push_back(v);
	}

	for (int i = 1; i <= n; i++) {
		if(!dfn[i]) {
			tarjan(i);
		}
	}
	
	for (int i = 1; i <= n; i++) {
		for (auto ne : e[i]) {
			if(scc[ne] != scc[i]) {
				in[scc[ne]]++;
				out[scc[i]]++;
			}
		}
	}

	int ans = 0;
	for (int i = 1; i <= cnt; i++) {
		ans += (in[i] == 0);
	}

	cout << ans << endl;
	return 0;
}

p2194

题意:

火烧情侣,回路的费用是一个点,其他的是相加,问费用最小。

思路:

用tarjan求强连通分量,把每个强连通分量的minm和cnt找出来,minm相加,cnt相乘取模就是答案

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 5;
#define int long long
int mod = 1000000007;

vector<int>e[N];
int dfn[N], low[N], tot;
int stk[N], instk[N], top;	// 栈的作用是记录正在访问的点
int scc[N], siz[N], cnt;	//最后的结果是scc[i] = k 记录第i个节点在第k个强连通分量里,大小是siz【k】
int cost[N];
int ans = 0, num = 1;
void tarjan(int x) {
	//入x时, 盖戳, 入栈
	dfn[x] = low[x] = ++tot;
	stk[++top] = x, instk[x] = 1;
	for (int y : e[x]) {
		if(!dfn[y]) {		//若y尚未访问
			tarjan(y);
			low[x] = min(low[x], low[y]);		//回x时更新low
		}
		else if(instk[y]) { //若y已访问且在栈中
			low[x] = min(low[x], low[y]);
		}
		// 剩下已经访问并且不在栈中的情况是y已经被访问完,不在枚举
	}
	//离x时,记录scc
	if(dfn[x] == low[x]) { //若x是scc的根
		int minm = 1000000000, t = 0;
		int y; ++cnt;
		do{		//陆续把强连通分量出栈
			y = stk[top--]; instk[y] = 0;
			if(cost[y] < minm) {
				t = 1;
				minm = cost[y];
			}
			else if(cost[y] == minm) {
				t++;
			}
			scc[y] = cnt; //scc编号
			++siz[cnt];   //scc大小
		} while(y != x);
		ans += minm;
		num = (num * t) % mod;
	}
} 

void solve() {
	int n;
	cin >> n;
	
	for (int i = 1; i <= n; i++) {
		cin >> cost[i];
	}

	int m;
	cin >> m;
	for (int i = 0, u, v; i < m; i++) {
		cin >> u >> v;
		e[u].push_back(v);
	}
	
	for (int i = 1; i <= n; i++) {
		if(!dfn[i]) {
			tarjan(i);
		}
	}

	cout << ans << " " << num << endl;
}

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);

	int T = 1; 
	while(T--) {
		solve();
	}

	return 0;
}

luogu p2341

题意:

n个点,m条边的有向图,有向边 u -> v 表示u喜欢v,喜欢可以传递,找出被所有牛喜欢的牛的个数。

思路:

缩点,如果是环就相互喜欢,根据传递性可以表示成一个点,然后统计出度为0的强连通分量的个数,如果是1个,输出这个强连通分量的大小,反之输出0.

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 1e5 + 5;

vector<int>e[N];
int dfn[N], low[N], tot;
int stk[N], instk[N], top;	// 栈的作用是记录正在访问的点
int scc[N], siz[N], cnt;	//最后的结果是scc[i] = k 记录第i个节点在第k个强连通分量里,大小是siz【k】
int in[N], out[N];

void tarjan(int x) {
	//入x时, 盖戳, 入栈
	dfn[x] = low[x] = ++tot;
	stk[++top] = x, instk[x] = 1;
	for (int y : e[x]) {
		if(!dfn[y]) {		//若y尚未访问
			tarjan(y);
			low[x] = min(low[x], low[y]);		//回x时更新low
		}
		else if(instk[y]) { //若y已访问且在栈中
			low[x] = min(low[x], low[y]);
		}
		// 剩下已经访问并且不在栈中的情况是y已经被访问完,不在枚举
	}
	//离x时,记录scc
	if(dfn[x] == low[x]) { //若x是scc的根
		int y; ++cnt;
		do{		//陆续把强连通分量出栈
			y = stk[top--]; instk[y] = 0;
			scc[y] = cnt; //scc编号
			++siz[cnt];   //scc大小
		} while(y != x);
	}
} 

void solve() {
	int n;
	cin >> n;

	int m;
	cin >> m;

	for (int i = 0, u, v; i < m; i++) {
		cin >> u >> v;
		e[u].push_back(v);
	}
	
	for (int i = 1; i <= n; i++) {
		if(!dfn[i]) {
			tarjan(i);
		}
	}

	map<pair<int, int>, bool>mp;
	for (int i = 1; i <= n; i++) {
		for (auto it : e[i]) {
			if(scc[i] != scc[it]) {
				in[scc[it]] ++;
				out[scc[i]] ++;
			}
		}
	}

	vector<int>v;
	
	for (int i = 1; i <= cnt; i++) {
		if(!out[i]) {
			v.push_back(i);
		}
	}

	if(v.size() == 1) {
		cout << siz[v[0]] << endl;
	}
	else {
		cout << 0 << endl;
	}
}

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);

	int T = 1; 
	while(T--) {
		solve();
	}

	return 0;
}

p2746

和p2812一样的体型,魔改了一下题意而已。

标签:cnt,20,int,scc,2024,++,low,instk
From: https://www.cnblogs.com/yyc4591/p/18024276

相关文章

  • 布客深度学习译文集 2024.2 更新
    Sklearn、TensorFlow与Keras机器学习实用指南第三版Sklearn与TensorFlow机器学习实用指南第二版PyTorch自然语言处理Transformer和扩散模型的生成式AI实用指南(预览版)Transformer自然语言处理面向程序员的FastAI和PyTorch深度学习TensorFlow学习手册Tensor......
  • P5057 [CQOI2006] 简单题
    原题链接题解区间修改+单点查询对于一个点,查询的时候翻转的次数如果是奇数,是1,如果是偶数,是0所以题目转变成对区间上的点加一,然后求单点的奇偶性树状数组对一串序列加1,相当于对其差分序列的\([l]++,[r+1]--\)code#include<bits/stdc++.h>usingnamespacestd;inta[10000......
  • 2024初三集训模拟测试2
    T0谜之阶乘题意:给定一个数\(x\),\(x\)为\(\dfrac{a!}{b!}\),求\(a\)和\(b\)。(多测,\(1\lex\le10^{18}\))阶乘增长很快,\(a\)和\(b\)的范围很小,所以直接暴力枚举即可。T1小P的2048点击查看题目根据题意模拟即可,根据方向决定遍历顺序比较方便。点击查看代码#incl......
  • 20240220
    每日whk是令人绷不住的。今日份背诵古诗:静女静女静女其姝,俟我于城隅。爱而不见,搔首踟蹰。静女其娈,贻我彤管。彤管有炜,说怿女美。自牧归荑,洵美且异。匪女之为美,美人之贻。涉江采芙蓉涉江采芙蓉涉江采芙蓉,兰泽多芳草。采之欲遗谁?所思在远道。还顾望旧乡,长路漫浩......
  • 2024.2.20
    今天把之前的fastbinattack第二个实例搞明白了,明天理一下记成笔记学了一些网络安全基础知识明天继续昨天遭到网络诈骗,把事情大概说了一下,结果是损失了一个价值挺高的账号和三千余元。现在说一下今天的后续,我通过平台在国外的官方平台客服,把我的账号找回了(损失的钱还没找回来),中......
  • 2024初三集训模拟测试2
    2024初三集训模拟测试2T1大模拟磨了1hour,T2想了45mins弃了(其实就差一点),T3暴力,T4暴力都没打。策略有问题。T1小P的2048本来是暑假集训原题。\(Shadow\)以41秒的成绩直接贺过,甚至估分于是miaomiao来找,喜提换题。所以\(Shadow\)薄纱了。\(\sqrt{}8\)......
  • 2024.2.20闲话——luogu5021随机选取边的正确性
    推歌:生きる(feat.可不)——水野あつ这首歌听完之后接着转去咖喱乌冬了,歌词甚至能接上,没绷住。刚刚写证明中间把wxy的杯子碰倒洒键盘上了,抢救键盘的过程中碰到缝就有水,有点涩。但是这个键盘里面怎么这么脏啊?下面来证luogu5021在菊花树中以任何顺序选取边并采取贪心策略的......
  • 【闲话】2024.2.20
    年前yspm让我写闲话,我说文笔不好且没啥可写的,今天确实有很多想写一下的,看int_R等人今天都写闲话了,比较蠢蠢欲动。昨天莫名放电影了,四机房自然是从自己找若干电影中公投一个下载,这次的选择范围是整个豆瓣TOP250!最终《看不见的客人》在《幸福终点站》《被解救的姜戈》《小丑......
  • 2024.2.20 横渡海峡 年轻的人
    数学很难。头一次感觉非常罚坐,但是细细思考还是很有收获的。ARC172F需要尝试对操作找出一个优秀的描述。手玩一下操作,偷一张题解的图:仅看这一段,可以发现我们的操作形如:插入一个字符,然后删除一个字符。做到这里已经是提高组题目了,令\(f_{i,j}\)表示\(S\)匹配到\(i\),\(T......
  • log4cplus在VS2022使用
    在VS2022使用vcpkg编译的log4cplus遇到以下错误:21:08:14:646 1>player.lib(player_manager.obj):errorLNK2001:无法解析的外部符号"void__cdecllog4cplus::detail::macro_forced_log(classlog4cplus::Loggerconst&,int,classstd::basic_string<wchar_t,structstd::ch......