POJ 1236

版权声明:Dream_dog专属 https://blog.csdn.net/Dog_dream/article/details/84671583

题意:一张有向图,一问至少给几个点发送软件,才能让所有点都能收到软件;二问是至少添加几条边才能让整个图是一个连通分量;
题解:先求连通分量然后再把同一个连通分量的点缩为一个点,再求所有点的入度和出度 答案一就是入度 答案二就是max(in,out) 注意:当只有一个连通分量时答案为0

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
using namespace std;
#define clr(a,b)  memset(a,b,sizeof(a))
#define il        inline
typedef long long ll;
const int maxn = 100 + 2;
const int minn = 130 + 1;

struct Edge {
	int to, nxt;
	Edge() {}
	Edge(int to, int nxt) :to(to), nxt(nxt) {}
}edge[maxn*maxn];
int n, tot, head[maxn];
int low[maxn], deep[maxn], in[maxn*maxn], out[maxn*maxn], link[maxn*maxn];//low最早的深度 deep实际深度 in入度 out出度 所属强连通分量
int Linksum, dep;
stack<int> sta;
void init()
{
	clr(edge, 0);
	clr(low, 0);
	clr(deep, 0);
	clr(in, 0);
	clr(out, 0);
	clr(link,0);
	while (!sta.empty()) { sta.pop(); }
	tot = Linksum = dep = 0;
	return;
}
void add(int a, int b)
{
	edge[++tot].to = b;
	edge[tot].nxt = head[a];
	head[a] = tot;
	return;
}
void Tarjan(int u)//求强连通分量一个点也代表一个
{
	low[u] = deep[u] = ++dep;
	sta.push(u);
	int t;
	for (int i = head[u]; i != 0; i = edge[i].nxt)
	{
		t = edge[i].to;
		if (!deep[t])
		{
			Tarjan(t);
			low[u] = min(low[u], low[t]);
		}
		else if (!link[t])
		{
			low[u] = min(low[u], deep[t]);
		}
	}
	if (low[u] == deep[u])
	{
		++Linksum;
		while (!sta.empty())
		{
			t = sta.top(); sta.pop();
			link[t] = Linksum;
			if (t == u) { break; }
		}
	}
	return;
}
void solve()
{
	for (int i = 1; i <= n; i++)
	{
		if (!deep[i]) { Tarjan(i); }
	}
	for(int k=1;k<=n;k++)//缩点
    {
        for (int i = head[k]; i != 0; i = edge[i].nxt)
			{
				int tm = edge[i].to;
				if (link[tm] != link[k])
				{
					out[link[k]]++;
					in[link[tm]]++;
				}
			}
    }
	int sumin = 0, sumout = 0;
	for (int i = 1; i <= Linksum; ++i)
	{
		sumin += in[i] ? 0 : 1;
		sumout += out[i] ? 0 : 1;
	}
	printf("%d\n%d\n", sumin, Linksum==1?0:max(sumout, sumin));
	return;
}
int main()
{
	int to;
	while (~scanf("%d", &n))
	{
		init();
		for (int i = 1; i <= n; ++i)
		{
            head[i]=0;
			while (scanf("%d", &to) && to)
			{
				add(i, to);
			}
		}
		solve();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Dog_dream/article/details/84671583