ybtoj 11.13 S组二分BFSD. 道路与航线

Posted SSL_ZZL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ybtoj 11.13 S组二分BFSD. 道路与航线相关的知识,希望对你有一定的参考价值。

ybtoj 11.13 S组 D. 道路与航线


题面


样例
样例输入1

4 6 1 4 
2 3 0 
1 2 1 
3 4 1 
4 3 0 
2 1 1 
1 3 1

样例输出1

3 5

样例2
去掉第一个c和第一个b。见选手附加文件。比完赛就没大数据了((((


解题思路

😅出题人良心,数据范围明明3*10^6,于是40分卡了一小时😅

方法一:二分答案,然后暴力bfs就好了
方法二:用vis[i]标记起点能不能到达 i

  • 如果 s 能走到 i,i 能走到 j ,那么 s 也能走到 j
  • 如果s 不能走到 i,i 能走到 j,但是不能保证后面加入边时 s 不能走到 i :将 i 和 j 连起来,下次连到 i 时,再做一个小bfs(i)

Code

方法一

#include <bits/stdc++.h>
#define N 3001000

using namespace std;

struct DT{
	int to, next;
}a[N * 2];
int n, m, S, T, l, r, mid, ans;
int num, head[N], v[N], x[N], y[N], id[N];
queue<int> q;

void add(int x, int y) {
	a[++ num] = (DT){ y, head[x] }, head[x] = num;
}

int check(int m) {
	memset(head, 0, sizeof(head));
	num = 0;
	for(int i = 1; i <= m; i ++) {
		add(x[i], y[i]);
		if(!id[i]) add(y[i], x[i]);
	}
	
	memset(v, 0, sizeof(v));
	while(!q.empty()) q.pop();
	q.push(S);
	while(!q.empty()) {
		int x = q.front();
		for(int i = head[x]; i; i = a[i].next) {
			int y = a[i].to;
			if(!v[y]) v[y] = 1, q.push(y);
			if(y == T) return 1;
		}
		q.pop();
	}
	return 0;
}

int main() {
	freopen("road.in", "r", stdin);
	freopen("road.out", "w", stdout);
	scanf("%d %d %d %d", &n, &m, &S, &T);
	for(int i = 1; i <= m; i ++)
		scanf("%d %d %d", &x[i], &y[i], &id[i]);
	l = 1, r = m;
	while(l <= r) {
		mid = (l + r) / 2;
		if(check(mid)) 
			ans = mid, r = mid - 1;
		else l = mid + 1;
	}
	printf("%d ", ans);
	l = 1, r = m, swap(S, T);
	while(l <= r) {
		mid = (l + r) / 2;
		if(check(mid)) 
			ans = mid, r = mid - 1;
		else l = mid + 1;
	}
	printf("%d", ans);
}

方法二

#include <bits/stdc++.h>
#define N 3001000

using namespace std;

struct DT{
	int to, next;
}a[N * 2];
int n, m, S, T, v[N], w[N][3];
int num, head[N];
queue<int> q;

void add(int x, int y) {
	a[++ num] = (DT){ y, head[x] }, head[x] = num;
}

int check(int x, int y, int T) {
	if(!v[x]) add(x, y);
	if(v[x] && !v[y]) {
		v[y] = 1, q.push(y);
		while(!q.empty()) {
			int xx = q.front();
			for(int i = head[xx]; i; i = a[i].next)
				if(!v[a[i].to]) q.push(a[i].to), v[a[i].to] = 1;
			q.pop();
		}
	}
	return v[T];
}

int find(int x, int y) {
	v[x] = 1;
	for(int i = 1; i <= m; i ++) {
		if(check(w[i][0], w[i][1], y)) return i;
		if(w[i][2] == 0 && check(w[i][1], w[i][0], y))
			return i;
	}
	return -1;
}

int read()
{
	char c = getchar();
	while(c<'0' || c>'9') c=getchar();
	int t = 0;
	while(c>='0' && c<='9')
	{
		t = t*10+c-'0';
		c=getchar();
	}
	return t;
}

int main() {
	freopen("road.in", "r", stdin);
	freopen("road.out", "w", stdout);
	n = read(), m = read(), S = read(), T = read();
	for(int i = 1; i <= m; i ++)
		w[i][0] = read(), w[i][1] = read(), w[i][2] = read();
	printf("%d ", find(S, T));
	
	memset(v, 0, sizeof(v));
	memset(head, 0, sizeof(head));
	num = 0;
	
	printf("%d", find(T, S));
} 

以上是关于ybtoj 11.13 S组二分BFSD. 道路与航线的主要内容,如果未能解决你的问题,请参考以下文章

ybtoj 11.13 S组贪心B. 字典之序

ybtoj 递推二分C. 3.无限序列

ybtoj 二分进阶A. 1.喂养宠物

ybtoj 二分进阶DPC. 3.攻击法坛

ybtoj 宽搜进阶二分A. 1.最小权值

ybtoj 宽搜进阶二分A. 1.最小权值