C - 班长竞选(Kosaraju算法

2023-05-16

题意:

在这里插入图片描述
input:

本题有多组数据。第一行 T 表示数据组数。每组数据开始有两个整数 N 和 M (2 <= n <= 5000, 0 <m <= 30000),接下来有 M 行包含两个整数 A 和 B(A != B) 表示 A 认为 B 合适。

output:

对于每组数据,第一行输出 “Case x: ”,x 表示数据的编号,从1开始,紧跟着是最高的票数。
接下来一行输出得票最多的同学的编号,用空格隔开,不忽略行末空格!

样例数据:
输入:

2
4 3
3 2
2 0
2 1

3 3
1 0
2 1
0 2

输出:

Case 1: 2
0 1
Case 2: 2
0 1 2

可供参考的另一个样例图:
在这里插入图片描述
(这个算法真的超级麻烦,要实现的东西超级多,所以从模板开始一点一点写)

思路:

经过分析可以知道,即能到达某一点的前面的点数最多的这个点,即为的票数最多的人。将图反向即可得到,这个点能到达的点的数量一定是最多的。同时图中可以存在环路,即有强连通分量。易知,这个点能到达的所有连通分量的点的和(自己所在的连通分量的点数需要减1,因为自己不能给自己投票)。即转化为先求图中的连通分量。然后开始跑反图,记录能到达的所有的连通分量的点的数量的和。

跑出连通分量:
在这里插入图片描述
两遍dfs跑出连通分量,其中逆后序序列很重要,第一遍在原图中跑出逆后序序列,模板如下:
在这里插入图片描述
跑出逆后序序列后,在反图中按照逆后序序列进行遍历,抛出scc,每次由起点遍历到的每个点在一构成一个scc。
在这里插入图片描述

代码模板:
在这里插入图片描述
在这里插入图片描述随后将scc进行缩点,记录下每个scc的点数和入度,容易票数最多的人一定在入度为0的scc中。
即以入度为0的scc在反图中往回跑,记录下能到达的所有的scc,并将点数全部加上。
缩点代码:
在这里插入图片描述
最后输出点数最多的,以及这个scc中所有的点。

总结:
其中要实现很多东西,比如后序逆序列,scc,还有缩点,缩点怎么缩,以及缩以后还要知道入度,也要反向遍历,以及缩点后的遍历入度为零的点,入度为零的点可能不止一个,其点的数量大小可能相同又可能不同,该记录下什么参数,最后将这些点输出来。在这个算法里,光是dfs就跑了很多次,每次的作用又不同,以及不断在正图和反图中来回切换的跑,又一次感受到菜鸡的难处。

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <string>
#include <queue>
#include <set> 
using namespace std;

int T, N, M, A, B;
int f[5010], f1[5010], vis[5010], c[5010], fcnt; //后序序列, ,标记,点在连通分量的标记 后续的下标

vector<int> G[5010], G1[5010], G2[5010]; //分别为原图,反图和缩点后的图
int cnt, Cnt[5010];  //scc的个数  , 连通分量中的点数
int Msum, tsum;    //记录最大的点数
vector<int> Mcnt;   //存放点数最大的连通分量的序号
set<int> SET[5010];  //缩点的时候,set可以过滤

void dfs1(int x) {   //确定原图的逆后序序列 
	vis[x] = 1;
	for (unsigned int i = 0; i < G[x].size(); i++) {
		if (!vis[G[x][i]])	dfs1(G[x][i]);
	}
	f[x] = fcnt++;
}

void dfs2(int x) {  //跑连通分量
	c[x] = cnt;   //记录点所在的连通分量的序号
	Cnt[cnt]++;  //记录连通分量中的点的数量
	for (unsigned int i = 0; i < G1[x].size(); i++) {
		if (!c[G1[x][i]]) dfs2(G1[x][i]);
	}
}

void dfs3(int x) {  //缩点后的图的遍历
	vis[x] = 1;
	tsum += Cnt[x];
	set<int>::iterator it;
	for (it = SET[x].begin(); it != SET[x].end(); it++) {
		if (!vis[*it])	dfs3(*it);
	}
}


//缩点求解 
void solve() {
	for (int i = 0; i < N; i++) { //缩点
		for (unsigned int j = 0; j < G[i].size(); j++) {
			if (c[i] == c[G[i][j]]) {
				continue;
			}
			else {
				G2[c[i]].push_back(c[G[i][j]]);  //缩点后正常的图,为判断入度
				SET[c[G[i][j]]].insert(c[i]);//过滤后的图,缩点后的图遍历得到点数
			}
		}
	}

	for (int i = 1; i <= cnt; i++) {  //查找入度为零的连通分量
		if (!G2[i].size()) {  //连通分量为0,则遍历,得到点数
			tsum = 0;
			memset(vis, 0, sizeof(vis));
			dfs3(i);
			if (tsum > Msum) { //因为入度为零的点可能不止一个,记录连通分量序号
				Msum = tsum;
				Mcnt.clear();
				Mcnt.push_back(i);
			}
			else if (tsum == Msum) {
				Mcnt.push_back(i);
			}
		}
	}

	int tmp = 0;
	cout << Msum - 1 << endl; //输出票数
	for (int j = 0; j < N; j++) {  //输出点的序号
		for (unsigned int l = 0; l < Mcnt.size(); l++) {
			if (c[j] == Mcnt[l]) {
				if (tmp == 0) {
					tmp = 1;
				}
				else {
					cout << " ";
				}
				cout << j ;
			}
		}
	}
	cout << endl;
}


int main() {
	ios::sync_with_stdio(0);
	cin >> T;
	for (int k = 0; k < T; k++) {
		cin >> N >> M;  //N个同学 ,M个关系

		//初始化 
		memset(f, 0, sizeof(f));
		memset(f1, 0, sizeof(f1));
		memset(vis, 0, sizeof(vis));
		memset(c, 0, sizeof(c));
		memset(Cnt, 0, sizeof(Cnt));
		fcnt = 0, cnt = 0, Msum = 0;
		for (int i = 0; i < N; i++) {
			G[i].clear(); G1[i].clear(); G2[i].clear(); SET[i].clear();
		}
		Mcnt.clear();

		for (int i = 0; i < M; i++) {
			cin >> A >> B;
			G[A].push_back(B);  //原图
			G1[B].push_back(A); //反图 	
		}

		for (int i = 0; i < N; i++) {
			if (!vis[i]) dfs1(i);
		}
		for (int i = 0; i < N; i++) {  //得到后序序列 
			f1[f[i]] = i;
		}

		for (int i = N - 1; i >= 0; i--) {
			if (c[f1[i]] == 0) {
				cnt++;
				dfs2(f1[i]);
			}
		}

		cout << "Case " << k + 1 << ":" << " ";
		solve();
	}
	return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C - 班长竞选(Kosaraju算法 的相关文章

随机推荐

  • 在 AlmaLinux 9安装Docker Compose

    首先先安装Docker 如何在 AlmaLinux 8 上安装和使用 Docker 检查Docker版本 docker version 安装Docker Compose sudo curl L 34 https github com doc
  • 使用python搭建一个简单的FTP服务器

    从配置文件获取访问FTP服务器目录的用户名 密码 span class token keyword from span pyftpdlib span class token punctuation span authorizers span
  • 更改win10系统C:\Users\中文用户名为英文用户名

    文章目录 前言一 打开注册表二 查找路径三 重启电脑四 将用中文名与英文名进行链接五 测试是否成功 前言 注意 xff1a 做之前请先浏览一遍 xff0c 做任何操作之前都建议不要直接就做 xff0c 先看一看文档中有哪些操作点是需要小心的
  • Cityscapes数据集的深度完整解析

    cityscapes数据集是分割模型训练时比较常用的一个数据集 xff0c 他还可以用来训练GAN网络生成街景图片 数据集下载和文件夹组成 xff1a 整个数据集包含50个欧洲城市 xff0c 5000张精细标注图像 标注位于gtFine文
  • 使用分支——处理Git merge 冲突

    使用分支 处理Git merge 冲突 版本控制系统就是负责管理来自于多个提交者 xff08 通常是开发者 xff09 之间的提交的 有时候多个开发者可能会编辑同一部分内容 一旦开发者A编辑了开发者B正在编辑的内容 xff0c 冲突就会产生
  • 纯手工解密几大在线js加密网站(1)

    0x0 开头 最近闲来无事 xff0c 来看一下目前网络上哪家加密工具的强度最高的 本人技术有限 xff0c 最终结果不能代表什么 xff0c 大家有遇到什么其他的js加密技术破解难题的 xff0c 也可以一起互相讨论 xff0c 也可以问
  • 纯手工解密几大在线js加密网站(3)

    0x0 开头 续接上章 xff0c 心血来潮想挨个破解一下各大js加密的网站 xff0c 了解一下现有的js加密的逻辑 0x1 介绍 Sojson支持js的不可逆混淆加密 xff0c 和很多高级的加密配置 xff0c 还增加了小白专用的一键
  • 如何在局域网内设置多个网段

    连接状态中的 属性 按钮 xff0c 选择 TCP IPv4 协议 xff0c 点击下面的 属性 按钮 xff0c 点击 高级 按钮 在高级TCP IP设置里面点击 添加 按钮 输入新网段的ip地址 xff08 以192网段为例 xff09
  • B-猫猫向前冲(拓扑排序

    题意 xff1a input 输入有若干组 xff0c 每组中的第一行为二个数N xff08 1 lt 61 N lt 61 500 xff09 xff0c M xff1b 其中N表示猫猫的个数 xff0c M表示接着有M行的输入数据 接下
  • 配置wsl2的图形界面

    1 更新源 span class token function sudo span span class token function apt get span update span class token function sudo s
  • 关于yyyyMMdd的正则表达式的使用

    String pattern 61 34 0 9 3 1 9 0 9 2 1 9 0 9 1 0 9 1 1 9 0 9 2 1 9 0 9 3 34 43 34 0 13578 1 02 0 1 9 12 0 9 3 01 0 469 1
  • qt下使用opencascade源代码

    c 43 43 基础太弱 xff0c 纠正一下 xff0c 在PRO中使用包含目录就可以使用 lt gt xff0c 将下载的opencascade文件通过make编译和安装 xff0c 添加引用就可以了 如果你依然对以下没用的操作感兴趣
  • Linux系统下CPU频率的调整

    省电 or 流畅 root 64 android sys devices system cpu cpu0 cpufreq cat scaling available governors hotplug conservative ondema
  • 禁止显示Apache目录列表-Indexes FollowSymLinks

    第一种方法 禁止显示Apache目录列表 Indexes FollowSymLinks 如何修改目录的配置以禁止显示 Apache 目录列表 缺省情况下如果你在浏览器输入地址 xff1a http localhost 8080 如果你的文件
  • 第十一章、远程联机服务器SSH / XDMCP / VNC / RDP

    维护网络服务器最简单的方式不是跑去实体服务器前面登入 xff0c 而是透过远程联机服务器联机功能来登入主机 xff0c 然后再来进行其他有的没的维护就是了 Linux 主机几乎都会提供 sshd 这个联机服务 xff0c 而且这个服务还是主
  • 如何查看电脑jdk/jre版本以及安装路径

    一 按快捷键win 43 r打开运行窗口 二 输入cmd 回车 xff0c 打开命令框 三 输入 java version 查看jdk版本 注意 xff1a java后面需要有空格 xff0c 不然会报错 java span class t
  • AndroidID、IMEI、OAID获取

    前言 因为项目中经常会遇到要上传一系列设备信息的功能 xff0c 为了方便使用 xff0c 所以就拆分成以下系列文章来单独介绍如何获取各类设备信息 手机运营商获取 AndroidID IMEI OAID获取 地理位置信息经纬度获取 公网IP
  • (二)裸机汇编--点亮LED

    目标 xff1a 点亮LED 1 查数据手册 硬件图中 xff0c 找到LED灯对应的GPIO 从二极管方向看出 xff0c 端口输出低电平时 xff0c 电流经过 xff0c LED点亮 再到数据手册查找对应的寄存器 GPBCON xff
  • Excel中将十六进制字符串转换为汉字的方法

    比如十六进制字符串 D0C2BDAE 转换方法是 在公式里面输入 61 CHAR HEX2DEC LEFT C6 4 amp CHAR HEX2DEC MID C6 5 4 其中C6 是十六进制所在的单元格 xff0c 原理很简单 xff0
  • C - 班长竞选(Kosaraju算法

    题意 xff1a input 本题有多组数据 第一行 T 表示数据组数 每组数据开始有两个整数 N 和 M 2 lt 61 n lt 61 5000 0 lt m lt 61 30000 xff0c 接下来有 M 行包含两个整数 A 和 B