POJ 1236 Network of Schools

大意不再赘述。

思路:

第1问:求一个有向图的最小点基。

第2问:求连接最小的边使得有向图变成一个强连通图。

最小点基怎么求?首先要去找最高强连通分量,即入度为0的强连通分量。最小点基就是从最高强连通分量中任选一个顶点,组成的顶点集B就是图G的一个最小点基。

连接最小的边使得有向图变为一个强连通图,即找入度为0与出度为0的最大值即可。

什么是最小权点基呢?设图G的每个顶点Vi都有一个非负的权值ai,使得顶点对应的权值ai之和最小的点基称为最小权点基。求最小权点基的算法是从最高强连通分量里取权值最小的顶点,组成最小权点基。

总结一下:最小点基是从最高强连通分量里任选一个顶点,组成最小点基。而最小权点基,是从最高强连通分量里取权值最小的顶点,组成最小权点基。

具体的题目有:POJ 1236(最小点基)、POJ 3592(最小权点基)

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;

const int MAXN = 1010;
const int MAXM = 10010;
const int INF = 0x3f3f3f3f;

struct Edge
{
	int v, next;
}edge[MAXM];

int n, m;
int cnt;
int scnt, top, tot;

int first[MAXN], dfn[MAXN], low[MAXN], ins[MAXN], stack[MAXN];
int belong[MAXN];
int ind[MAXN], outd[MAXN];

void init()
{
	cnt = 0;
	scnt = tot = top = 0;
	memset(first, -1, sizeof(first));
	memset(ind, 0, sizeof(ind));
	memset(outd, 0, sizeof(outd));
	memset(ins, 0, sizeof(ins));
}

void read_graph(int u, int v)
{
	edge[cnt].v = v;
	edge[cnt].next = first[u], first[u] = cnt++;
}

void dfs(int u)
{
	int v;
	low[u] = dfn[u] = ++tot;
	ins[u] = 1;
	stack[top++] = u;
	for(int e = first[u]; e != -1; e = edge[e].next)
	{
		v = edge[e].v;
		if(!dfn[v])
		{
			dfs(v);
			low[u] = min(low[u], low[v]);
		}
		else if(ins[v])
		{
			low[u] = min(low[u], dfn[v]);
		}
	}
	if(low[u] == dfn[u])
	{
		scnt++;
		do
		{
			v = stack[--top];
			belong[v] = scnt;
			ins[v] = 0;
		}while(u != v);
	}
}

void Tarjan()
{
	for(int i = 1; i <= n; i++) if(!dfn[i])
		dfs(i);
}

void read_case()
{
	init();
	for(int u = 1; u <= n; u++)
	{
		int v;
		while(scanf("%d", &v) && v)
		{
			read_graph(u, v);
		}
	}
}

void solve()
{
	read_case();
	Tarjan();
	for(int u = 1; u <= n; u++)
	{
		for(int e = first[u]; e != -1; e = edge[e].next)
		{
			int v = edge[e].v;
			if(belong[u] != belong[v])
			{
				outd[belong[u]]++;
				ind[belong[v]]++;
			}
		}
	}
	int ans1 = 0, ans2 = 0;
	for(int i = 1; i <= scnt; i++)
	{
		if(!ind[i]) ans1++;
		if(!outd[i]) ans2++;
	}
	printf("%d\n", ans1);
	printf(scnt == 1? "0\n":"%d\n", max(ans1, ans2));
}

int main()
{
	while(~scanf("%d", &n))
	{
		solve();
	}
	return 0;
}

你可能感兴趣的:(POJ 1236 Network of Schools)