POJ 1236 Network of Schools(强连通分量)

本文探讨了通过最小化软件分发次数及调整分发列表来确保软件能高效地覆盖整个教育网络的方法。利用图论中的强连通分量概念,提出了一种算法,该算法能够确定最少的软件复制次数,并通过添加最少数量的接收者来实现网络中的完全覆盖。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:题意杀...网络中的一学校可以将软件发送给其他一些学校,能够发送给谁取决于他们各自维护的一个清单。将学校看成一个节点,给出每个学校的维护清单,问至少需要复制几次软件,使毎个学校都能够得到该软件。然后问在清单中至少添加几项,可使软件只要复制一次,所有学校都可以得到

思路:和HDU2767一样,最少加多少条边使得图强连通

        1.    求出该图的所有强连通分量.

        2.    将每个分量缩点构新DAG图.

        3.    第一问就是新图中入度为0点的个数,第二问是max(入度0点数,出度0点数)

注意:当原本就是强连通的时候要特判


#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <set>
#include <ctime>
#include <cmath>
#include <cctype>
#include <stack>
using namespace std;
#define maxn 100+10
#define LL long long
int cas=1,T;
vector<int>G[maxn];
int pre[maxn];
int lowlink[maxn];
int sccno[maxn];
int dfs_clock,scc_cnt;
int n,m;
stack<int>S;
void dfs(int u)
{
	pre[u]=lowlink[u]=++dfs_clock;
	S.push(u);
	for (int i = 0;i<G[u].size();i++)
	{
		int v = G[u][i];
		if (!pre[v])
		{
			dfs(v);
			lowlink[u] = min(lowlink[u],lowlink[v]);
		}
		else if (!sccno[v])
		{
			lowlink[u] = min (lowlink[u],pre[v]);
		}
	}
	if (lowlink[u] == pre[u])
	{
		scc_cnt++;
		for (;;)
		{
			int x = S.top();S.pop();
			sccno[x] = scc_cnt;
			if (x==u)
				break;
		}
	}
}

void find_scc(int n)
{
	dfs_clock=scc_cnt=0;
	memset(sccno,0,sizeof(sccno));
	memset(pre,0,sizeof(pre));
	for (int i = 1;i<=n;i++)
		if (!pre[i])
			dfs(i);
}
int in[maxn];
int out[maxn];
int main()
{
	//freopen("in","r",stdin);
	while (scanf("%d",&n)!=EOF && n)
	{	
		memset(in,0,sizeof(in));
		memset(out,0,sizeof(out));
		for (int i = 0;i<=n;i++)
			G[i].clear();
		for (int u=1;u<=n;u++)
		{
			int v;
			while (scanf("%d",&v) && v)
			{
				G[u].push_back(v);
			}
		}
		find_scc(n);
		for (int i = 1;i<=scc_cnt;i++)
		{
            in[i]=out[i]=1;
		}
		for (int u = 1;u<=n;u++)
			for (int i =0;i<G[u].size();i++)
			{
				int v = G[u][i];
				if (sccno[u] != sccno[v])
					in[sccno[v]]=out[sccno[u]]=0;
			}
		int a=0,b=0;
		for (int i = 1;i<=scc_cnt;i++)
		{
			if (in[i])
				a++;
			if (out[i])
				b++;
		}
		if (scc_cnt !=1)
		    printf("%d\n%d\n",a,max(a,b));
		else
			printf("1\n0\n");

	}
	return 0;
}


Description

A number of schools are connected to a computer network. Agreements have been developed among those schools: each school maintains a list of schools to which it distributes software (the “receiving schools”). Note that if B is in the distribution list of school A, then A does not necessarily appear in the list of school B 
You are to write a program that computes the minimal number of schools that must receive a copy of the new software in order for the software to reach all schools in the network according to the agreement (Subtask A). As a further task, we want to ensure that by sending the copy of new software to an arbitrary school, this software will reach all schools in the network. To achieve this goal we may have to extend the lists of receivers by new members. Compute the minimal number of extensions that have to be made so that whatever school we send the new software to, it will reach all other schools (Subtask B). One extension means introducing one new member into the list of receivers of one school. 

Input

The first line contains an integer N: the number of schools in the network (2 <= N <= 100). The schools are identified by the first N positive integers. Each of the next N lines describes a list of receivers. The line i+1 contains the identifiers of the receivers of school i. Each list ends with a 0. An empty list contains a 0 alone in the line.

Output

Your program should write two lines to the standard output. The first line should contain one positive integer: the solution of subtask A. The second line should contain the solution of subtask B.

Sample Input

5
2 4 3 0
4 5 0
0
0
1 0

Sample Output

1
2


### 链式线性表的实验内容 链式线性表是一种通过指针连接节点数据结构,其核心在于动态分配内存并建立节点之间的逻辑关系。以下是关于链式线性表的一些常见实验内容: #### 单链表的基本操作 单链表是最简单的链式线性表形式,其实现通常包括以下功能[^2]: 1. **创建单链表**: 可以按照逆位序(从表头插入)或正位序(从表尾插入)的方式构建链表。 2. **遍历链表**: 输出链表中的所有元素。 3. **查找节点**: 给定一个关键字,在链表中找到对应的节点位置。 4. **插入节点**: 在指定位置前/后插入新节点。 5. **删除节点**: 删除指定位置上的节点或者具有特定值的节点。 这些基本操作构成了学习链式线性表的基础部分。 ```c++ // 插入节点函数示例 (C++) void insertNode(Node* &head, int value) { Node* newNode = new Node; newNode->data = value; newNode->next = nullptr; if (!head) { // 如果链表为空,则直接设置为头结点 head = newNode; } else { Node* temp = head; while (temp->next != nullptr) { // 找到最后一个节点 temp = temp->next; } temp->next = newNode; // 将新节点附加到末尾 } } ``` --- ### 提升训练建议 为了进一步掌握链式线性表的应用能力,可以尝试完成一些更复杂的题目和项目实践: 1. **双向链表的操作** - 实现双端队列的功能,支持在头部和尾部进行高效的插入与删除操作。 - 编写程序模拟浏览器的历史记录管理器,允许前进和回退页面访问历史。 2. **循环链表的设计** - 构建一个基于循环链表的游戏场景,比如约瑟夫环问题,解决如何安全退出游戏的问题。 3. **复杂数据处理** - 使用链表存储学生信息(姓名、学号、成绩),设计菜单驱动界面实现增删改查等功能。 - 结合文件读取技术,加载外部数据源初始化链表,并保存修改后的状态至磁盘。 4. **性能优化挑战** - 对于大规模数据集下的频繁查询需求,考虑引入哈希映射辅助定位目标节点的位置,从而减少时间开销。 以上提到的各种扩展任务不仅能够加深对理论知识的理解程度,还能培养实际编程技巧以及解决问题的能力[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值