添边问题

损坏的传送门

题目大意

没有环的有向图称为有向无环图,这是一个多么美好的结构吖。

如果有一张有 N N N 个点的有向图,我们可能需要删掉一些边使它变成一张有向无环图。假设初始时我们只有 N N N 个互不相连的点,当然它也是一张有向无环图。依次给出 T T T 条边和每条边的方向。 每给出一条边就要立即决定是否要加入这一条边,使得这张图始终是一张有向无环图(意思是:按顺序处理每条边,能加就加,让你模拟这个过程,自环不能加入)。计算在满足要求的情况下一共有多少条边没有被加入。如果所有边都可以加入这张图则输出 0 0 0

注意有向无环图是可以存在重边的。即:若原图有边 1 → 2 1 \to 2 12,则新边 1 → 2 1 \to 2 12 可被加入。

对于 100 % 100\% 100% 的数据, n < = 250 n<=250 n<=250 T < = 100000 T<=100000 T<=100000

解题思路

用一个数组 Map 记录 u u u 是否可以到达 v v v

对于一组输入的边 u → v u \to v uv,其需要经历一下流程:

  1. 如果 v v v 可达 u u u,说明如果建了 u → v u \to v uv,就形成了一个环,答案加 1 1 1
  2. 如果已经有一条边 u → v u \to v uv 了,那么当前输入的这条边不再需要执行任何操作,直接跳过。
  3. 用两个临时数组 a a a b b b 记录有哪些点可达点 u u u,以及点 v v v 可达哪些点。
  4. 双重循环遍历两个数组,将 M a p [ a i ] [ b j ] Map[a_i][b_j] Map[ai][bj] 标记为 1 1 1,因为将边 u → v u \to v uv 加上后,这些点都可以到达。

其实这道题用记忆化搜索也可以。

就是对于一组输入的边 u → v u \to v uvdfs 一下,判断 v v v 是否可达 u u u

  • 若可以到达,则不加上这条边。
  • 若不能到达,则加上这条边。

dfs 的话用数组记录答案就行了,避免重复地 dfs

其实这题还可以改改, m a n g o 13 mango13 mango13 曰:可以将本题改成强制离线(这题是在线判断的)的。

以下目前我的思路,期待被 HACK

先用有向图 Tarjan 判环,然后循环一下所有的边,记录强连通分量里有多少条边。

则将强连通分量拆成有向无环图,就需要拆 m − n + 1 m-n+1 mn+1 条边( m m m 是强连通分量里的边的数量, n n n 是强连通分量里的点的数量)。

正在创数据中~~~

等待更新~~~

AC CODE

#include <bits/stdc++.h>
using namespace std;

int Map[251][251];
int a[251], b[251];
int al, bl, ans;
int n, m, u, v;

signed main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; ++i)
		Map[i][i] = 1;
	while (m--)
	{
		cin >> u >> v;
		if (Map[v][u])
		{
			++ans;
			continue;
		}
		if (Map[u][v])
			continue;
		al = bl = 0;
		for (int i = 1; i <= n; ++i)
			if (Map[i][u])
				a[++al] = i;
		for (int i = 1; i <= n; ++i)
			if (Map[v][i])
				b[++bl] = i;
		for (int i = 1; i <= al; ++i)
			for (int j = 1; j <= bl; ++j)
				Map[a[i]][b[j]] = 1;
	}
	cout << ans;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值