强连通分量

在一场怪兽互殴的游戏中,贝爷训练了N只怪兽,通过一对一对决来确定至少有多少只怪兽能存活。游戏结果由N*N的矩阵表示,每个元素代表两只怪兽对决的结果。本文介绍了一种算法,用于计算在所有可能的对决顺序下,至少能有多少只怪兽存活。

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

Description
贝爷的人生乐趣之一就是约战马会长. 他知道马会长喜欢和怪兽对决,于是他训练了N只怪兽,并对怪兽用0到N-1的整数进行编号. 贝爷训练怪兽的方式是让它们一对一互殴. 两只怪兽互殴会发生以下三种可能的结果:
1) 什么事也没发生
2) 第一只怪兽永远消失
3) 第二只怪兽永远消失
怪兽们经过了旷日持久的互殴. 贝爷不知道哪些怪兽进行了互殴也不知道它们互殴的顺序,但他确信无论经过多少次互殴,总有一些怪兽能存活下来,他将要派这些怪兽去和马会长对决. 现在他想知道至少有多少只怪兽能存活下来,你能帮他算出来吗?

请实现下面Solution类中的minLeftMonsters函数,完成上述功能.
参数G: N*N(1 <= N <= 50)字符矩阵,G[i][j]表示怪兽i和怪兽j互殴会发生的结果. 字符‘+’代表怪兽i会消失,’-’代表怪兽j会消失,数字’0’则代表什么都没发生. 输入保证G[i][i]一定是’0’,而且G[i][j]和G[j][i]一定相反(’-’和’+’互为相反,’0’和自身相反).
返回值:怪兽存活的最少数目.

class Solution {

public:
    int minLeftMonsters(vector< vector<char> > G) {}

}

 

class Solution {
private:
	vector<int> pre, lowlink, sccno;
	stack<int> S;
	vector< vector<int> > V;
	vector<bool> vis;
	int dfs_clock, scc_cnt;
	void dfs(int u)
	{
		pre[u] = lowlink[u] = ++ dfs_clock;
		S.push(u);
		for (int i=0; i<V[u].size(); i++)
		{
			int v = V[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;
		for (int i=0; i<n; i++) sccno[i] = pre[i] = 0;
		for (int i=0; i<n; i++) if (!pre[i]) dfs(i);
	}
public:
	int minLeftMonsters(vector< vector<char> > G) {
		int res, n, x, i, j;
		n = G.size();
		V.resize(n);
		pre.resize(n);
		lowlink.resize(n);
		sccno.resize(n);
		vis.resize(n + 1);
		for (i=0; i<n; i++)
			for (j=0; j<n; j++)
				if (G[i][j] == '-') V[i].push_back(j);
		find_scc(n);
		for (i=1; i<=scc_cnt; i++) vis[i] = false;
		res = scc_cnt;
		for (i=0; i<n; i++)
			for (j=0; j<V[i].size(); j++)
			{
				x = sccno[V[i][j]];
				if (x == sccno[i]) continue;
				if (!vis[x])
				{
					res --;
					vis[x] = true;
				}
			}
		for (i=0; i<n; i++) V[i].clear();
		V.clear();
		pre.clear();
		lowlink.clear();
		sccno.clear();
		vis.clear();
		while (!S.empty()) S.pop();
		return res;	
	}
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值