【C - 班长竞选】

题意:

大学班级选班长,N 个同学均可以发表意见 若意见为 A B 则表示 A 认为 B 合适,意见具有传递性,即 A 认为 B 合适,B 认为 C 合适,则 A 也认为 C 合适 勤劳的 TT 收集了M条意见,想要知道最高票数,并给出一份候选人名单,即所有得票最多的同学。

思路:

从图中找出所有强连通分量进行缩点,那么首先某一个强连通分量中的人获得了该强连通分量中节点数目减一得票数。他们还会获得其他与之相连的强连通分量的票数。
计算出每个节点对应的连通分量:利用dfs计算出图的后序序列,根据逆后序序列遍历反向图,构建强连通分量,根据构建出的强连通分量进行缩点得到缩点后的图,并记录下缩点后对应的内部节点个数,遍历每一个节点,通过dfs利用连通分量计算得到的投票数,找出最大投票数,并找出对应的的节点。

代码:

#include
#include
using namespace std;
const int N = 5010;
const int M = 30010;
int head1[N], head2[N], head[N], ind[N], c[N], dfn[N], vis[N], scc[N], judge[N], belong[N];
int inx, num, dcnt, scnt, tot1, tot2, tot;
struct Edge {
	int to, next;
}e1[M], e2[M], e[M];
void add1(int x, int y)//原图
{
	e1[++tot1].next = head1[x];
	e1[tot1].to = y;
	head1[x] = tot1;
}
void add2(int x, int y)//反图
{
	e2[++tot2].next = head2[x];
	e2[tot2].to = y; 
	head2[x] = tot2;
}
void add(int x, int y)//缩点图
{
	e[++tot].next = head[x];
	e[tot].to = y;
	head[x] = tot;
	ind[y]++;
}
void dfs1(int x)
{
	vis[x] = 1;
	for (int i = head1[x]; i != 0; i = e1[i].next)
	{
		int v = e1[i].to;
		if (!vis[v])
			dfs1(v);
	}
	dfn[++dcnt] = x;
}
void dfs2(int x)
{
	c[x] = scnt;
	scc[scnt]++;//记录当前缩点里点的个数
	for (int i = head2[x]; i != 0; i = e2[i].next)
	{
		int v = e2[i].to;
		if (!c[v])
			dfs2(v);
	}
}
void dfs(int x)
{
	num += scc[x];
	vis[x] = 1;
	for (int i = head[x]; i != 0; i = e[i].next)
	{
		int v = e[i].to;
		if (!vis[v])
			dfs(v);
	}
}
void kosaraju(int n)
{
	dcnt = 0, scnt = 0;
	memset(c, 0, sizeof(c));//0-n-1有效 存储缩点号
	memset(dfn, 0, sizeof(dfn));
	memset(vis, 0, sizeof(vis));
	for (int i = 0; i < n; i++)
		if (!vis[i])
			dfs1(i);
	for (int i = n; i >= 1; i--)//按逆后序缩点
		if (!c[dfn[i]])
		{
			++scnt;
			dfs2(dfn[i]);
		}
}
void spt(int n)//构造缩点图
{
	for (int x = 0; x < n; x++)
	{
		for (int i = head2[x]; i != 0; i = e2[i].next)
		{
			int v = e2[i].to;
			if (c[x] == c[v])continue;
			add(c[x], c[v]);

		}
	}
}
void solve(int n)
{
	kosaraju(n);
	spt(n);
	int maxn = 0;//maxn:最高票数
	memset(belong, 0, sizeof(belong));
	for (int i = 1; i <= scnt; i++)//缩点
	{
		if (ind[i] == 0)
		{
			memset(vis, 0, sizeof(vis));
			num = 0;
			dfs(i);
			belong[i] = num - 1;//除了自己
			if (num - 1 > maxn)
				maxn = num - 1;
		}
	}
	printf("Case %d: %d\n", inx, maxn);
	inx++;
	memset(judge, 0, sizeof(judge));
	for (int i = 1; i <= scnt; i++)
		if (belong[i] == maxn)
			judge[i] = 1;
	int ix = 0;
	for (int i = 0; i < n; i++)
	{
		if (judge[c[i]])
		{
			if (ix)
				printf(" %d", i);
			else
				printf("%d", i);
			ix++;
		}
	}
	printf("\n");
}
void ini()
{
	memset(head1, 0, sizeof(head1));//0也有效
	memset(head2, 0, sizeof(head2));
	memset(head, 0, sizeof(head));
	memset(ind, 0, sizeof(ind));
	memset(scc, 0, sizeof(scc));
	tot = 0, tot1 = 0, tot2 = 0;
}
int main()
{
	int t;
	scanf("%d", &t);
	inx = 1;
	while (t--)
	{
		ini();
		int n, m;
		scanf("%d %d", &n, &m);
		for (int i = 0; i < m; i++)
		{
			int a, b;
			scanf("%d %d", &a, &b);
			add1(a, b);
			add2(b, a);
		}
		solve(n);
	}
}

你可能感兴趣的:(【C - 班长竞选】)