【BZOJ4484】【JSOI2015】最小表示

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/79980421

【题目链接】

【思路要点】

  • 单独考虑每个点的出边,这些问题是相互独立的。
  • 对原图拓扑排序,按照拓扑序解决问题。
  • 将每个点的出边按照所到达的点的拓扑序从大到小排序。
  • 若一条出边到达的点还不能由当前点到达,保留这条边,并更新当前点可达的节点集合,否则删除这条边。
  • 该过程显然可以用bitset优化。
  • 时间复杂度\(O(\frac{N*M}{w}+MLogM)\),其中\(w=64\)。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 30005;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
int n, m, dfn[MAXN];
int d[MAXN], q[MAXN];
vector <int> a[MAXN], b[MAXN];
bitset <MAXN> res[MAXN];
bool cmp(int x, int y) {return dfn[x] > dfn[y]; }
int main() {
	read(n), read(m);
	for (int i = 1; i <= m; i++) {
		int x, y;
		read(x), read(y);
		a[x].push_back(y);
		b[y].push_back(x);
		d[x]++;
	}
	int l = 1, r = 0;
	for (int i = 1; i <= n; i++)
		if (d[i] == 0) q[++r] = i;
	while (l <= r) {
		int tmp = q[l++];
		for (unsigned i = 0; i < b[tmp].size(); i++)
			if (--d[b[tmp][i]] == 0) q[++r] = b[tmp][i];
	}
	for (int i = 1; i <= n; i++) {
		res[i].reset();
		res[i].set(i);
		dfn[q[i]] = i;
	}
	int cnt = 0;
	for (int i = 1; i <= n; i++) {
		int tmp = q[i];
		sort(a[tmp].begin(), a[tmp].end(), cmp);
		for (unsigned j = 0; j < a[tmp].size(); j++) {
			int dest = a[tmp][j];
			if (!res[tmp][dest]) {
				cnt++;
				res[tmp] |= res[dest];
			}
		}
	}
	printf("%d\n", m - cnt);
	return 0;
}

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页