SCC重新建图

Tarjan或Kosaraju算法【对每个点归类belong】求出SCC之后,对num_scc个SCC重新建图,针对不同问题,考虑重边的问题。

//**************************************重构图****************************************//
void init_rebuild(void)
{
	rebuild_ALG->n=num_scc;
	for(int i=1;i<=num_scc;i++)
	{
		rebuild_ALG->vlist[i].vertex=i;
		rebuild_ALG->vlist[i].firstedge=NULL;

		in_d[i]=0;
		out_d[i]=0;
	}
}

void add_edge_To_ALG(int par,int son)
{
	ENode *ptr=(ENode *)malloc(sizeof(ENode));

	ptr->key=son;
	ptr->next=rebuild_ALG->vlist[par].firstedge;
	rebuild_ALG->vlist[par].firstedge=ptr;
}

void rebuild_ALGraph(void)
{
	int par,son;
	int in_par_scc;  //判断是否已在par的scc中
	ENode *ptr=(ENode *)malloc(sizeof(ENode));
	ENode *ep=(ENode *)malloc(sizeof(ENode));

	for(int i=0;i<ALG->n;i++)
	{
		par=i;
		in_par_scc=0;
		ptr=ALG->vlist[par].firstedge;
		while(ptr!=NULL)
		{
			son=ptr->key;
			if(belong[par] != belong[son])
			{
				ep=rebuild_ALG->vlist[belong[par]].firstedge;//考虑重边问题
				while(ep!=NULL)
				{
					if(ep->key == belong[son])
					{
						in_par_scc=1;
						break;
					}
					ep=ep->next;
				}
				if(!in_par_scc)
				{
				    add_edge_To_ALG(belong[par],belong[son]);
					in_d[belong[son]]++;
					out_d[belong[par]]++;
				}
			}
			ptr=ptr->next;
		}
	}
}
//***************************************************************************//


# P3530 [POI 2012] FES-Festival ## 题目背景 在 Byteburg 举办了一场慈善活动,你是其中一个筹款人。不幸的是,你错过了一些有趣的活动,包括一场越野赛。 谜题爱好者 Byteasar 承诺:如果你能解开他的谜题,他会捐一大笔钱。 ## 题目描述 你不知道越野赛的结果,但 Byteasar 会告诉你部分信息。现在,他要你答出:所有参赛者最多能达到多少种不同的成绩,而不违背他给的条件。(他们中的一些人可能平局,也就是同时到达终点,这种情况只算有一种成绩)。 Byteasar 告诉你,所有参赛者的成绩都是整数秒。他还会为你提供了一些参赛者成绩的关系。具体是:他会给你一些数对 $(A, B)$,表示 $A$ 的成绩正好比 $B$ 快 $1$ 秒;他还会给你一些数对 $(C, D)$,表示 $C$ 的成绩不比 $D$ 慢。而你要回答的是:所有参赛者最多能达到多少种不同的成绩,而不违背他给的条件。 请你编程解决这个谜题。 ## 输入格式 第一行有三个整数 $n, m_{1}, m_{2}$,分别表示选手人数、数对 $(A, B)$ 的数目、数对 $(C, D)$ 的数目。 接下来 $m_1$ 行,每行两个整数 $a_{i}, b_{i}$($a_{i} \ne b_{i}$)。这表示选手 $a_{i}$ 的成绩恰比 $b_{i}$ 小 $1$ 秒。 接下来 $m_{2}$ 行,每行两个整数 $c_{i}, d_{i}$($c_{i} \ne d_{i}$)。这表示选手 $c_{i}$ 的成绩不比 $d_{i}$ 的成绩差(也就是花的时间不会更多)。 ## 输出格式 如果有解,输出一行一个整数,表示所有选手最多能拿到的成绩的种数。 如果无解,输出 `NIE`。 ## 输入输出样例 #1 ### 输入 #1 ``` 4 2 2 1 2 3 4 1 4 3 1 ``` ### 输出 #1 ``` 3 ``` ## 说明/提示 答案为 $3$,情况为:$t_3=1, t_1=t_4=2, t_2=3$。 ($t_i$ 表示参赛者 $i$ 花的时间) **【数据范围】** 对于 $15\%$ 的数据,$n \le 10$。 对于 $100\%$ 的数据,$2 \le n \le 600$,$1 \le m_{1} + m_{2} \le {10}^5$。 代码: ```cpp #include <bits/stdc++.h> using namespace std; const int INF = 0x3f3f3f3f; const int MAX_N = 650; int n, m1, m2, cnt, scc[MAX_N]; int dis[MAX_N][MAX_N], mx[MAX_N]; int dfn[MAX_N], low[MAX_N], tim; stack<int> stk; vector<int> e[MAX_N]; void Tarjan(int u) { dfn[u] = low[u] = ++tim; stk.push(u); for (int v : e[u]) { if (!dfn[v]) { Tarjan(v); low[u] = min(low[u], low[v]); } else if (!scc[v]) low[u] = min(low[u], dfn[v]); } if (dfn[u] == low[u]) { scc[u] = ++cnt; while (stk.top() != u) { scc[stk.top()] = cnt; stk.pop(); } stk.pop(); } } int main() { memset(dis, 0x3f, sizeof(dis)); for (int i = 1; i <= n; i++) dis[i][i] = 0; cin >> n >> m1 >> m2; for (int a, b; m1--; ) { cin >> a >> b; e[a].push_back(b); e[b].push_back(a); dis[a][b] = min(dis[a][b], 1); dis[b][a] = min(dis[b][a], -1); } for (int c, d; m2--; ) { cin >> c >> d; e[d].push_back(c); dis[d][c] = min(dis[d][c], 0); } for (int i = 1; i <= n; i++) if (!dfn[i]) Tarjan(i); for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++) if (scc[i] == scc[k] && dis[i][k] != INF) for (int j = 1; j <= n; j++) if (scc[i] == scc[j]) dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]); for (int i = 1; i <= n; i++) if (dis[i][i] < 0) { cout << "NIE"; return 0; } for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) if (scc[i] == scc[j]) mx[scc[i]] = max(mx[scc[i]], dis[i][j] + 1); cout << accumulate(mx + 1, mx + cnt + 1, 0) << '\n'; return 0; } ``` 为什么WA了
最新发布
08-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值