[ybt gold navigation 3-5-5] [luogu P1262] spy network

Posted by rage123456 on Fri, 11 Feb 2022 19:33:25 +0100

Spy network

Title Link: ybt gold navigation 3-5-5 / luogu P1262

General idea of the topic

There are some people, some of them, you can catch them, and then there is a fee.
Then after a person is caught, he can help you catch some people.
Ask if you can catch everyone with the minimum cost. If you can output the minimum cost, otherwise output the person with the smallest number who can't be caught.

thinking

In fact, it's easy to think of this problem as a connection.
If a person in a ring is caught, the ring is finished. Just shrink it up.

What do you want to record? If you only choose one person to catch in the ring, you must choose the one with the lowest cost, so you should record the minimum weight in the point. (if no one can use it) − 1 -1 − 1)
Then you think that if not everyone is caught, you have to find the point caught that contains the smallest number in the original point, so you have to record that this point contains the smallest number in the original point.

It's not difficult to know that the degree of penetration in the picture is 0 0 0 point, if this point can't be grasped N O NO NO, otherwise the total cost will be added with the minimum cost to be caught at this point.

Then the question is, if so N O NO NO, how to find the minimum number that hasn't been caught.
Consider finding the points that can be caught first. Put the points that can be caught in the figure into a queue, and then run bfs to get all the points that can be caught.
And then we're going from 0 0 0, the points that cannot be caught are also put into a queue, and then run bfs to find all the points that will not be caught. (if you encounter points you have encountered before or can be caught, you can't go down) then these points include the answer with the smallest number in the original points.

code

#include<cstdio>
#include<queue>
#include<cstring>
#include<iostream>

using namespace std;

struct node {
	int to, nxt;
}e[8001], e_[8001];
int n, p, cost[3001], x, y, r;
int le[3001], KK, dfn[3001], low[3001], in[3001];
int sta[3001], tmp, tot, size[3001], val[3001], inn[3001];
int le_[3001], KK_, ru[3001], minn[3001], minnans, ans;
queue <int> q, qq;
bool noans;

void add(int x, int y) {
	e[++KK] = (node){y, le[x]}; le[x] = KK;
}

void tarjan(int now) {//Shrinking point
	dfn[now] = low[now] = ++tmp;
	sta[++sta[0]] = now;
	
	for (int i = le[now]; i; i = e[i].nxt)
		if (!dfn[e[i].to]) {
			tarjan(e[i].to);
			low[now] = min(low[now], low[e[i].to]);
		}
		else if (!in[e[i].to]) low[now] = min(low[now], low[e[i].to]);
	
	//When shrinking the point, record whether someone at this point can be caught by you, the one with the lowest cost (which one you want to catch) and the smallest number between them
	if (dfn[now] == low[now]) {
		in[now] = ++tot;
		size[tot]++;
		val[tot] = cost[now];
		minn[tot] = now;
		while (sta[sta[0]] != now) {
			in[sta[sta[0]]] = tot;
			size[tot]++;
			if (val[tot] == -1) val[tot] = cost[sta[sta[0]]];
				else if (cost[sta[sta[0]]] != -1) val[tot] = min(val[tot], cost[sta[sta[0]]]);
			minn[tot] = min(minn[tot], sta[sta[0]]);
			sta[0]--;
		}
		sta[0]--;
	}
}

void add_(int x, int y) {
	e_[++KK_] = (node){y, le_[x]}; le_[x] = KK_;
	ru[y]++;
}

int main() {
	memset(cost, -1, sizeof(cost));
	
	scanf("%d %d", &n, &p);
	for (int i = 1; i <= p; i++) {
		scanf("%d %d", &x, &y);
		cost[x] = y;
	}
	
	scanf("%d", &r);
	for (int i = 1; i <= r; i++) {
		scanf("%d %d", &x, &y);
		add(x, y);
	}
	
	for (int i = 1; i <= n; i++)
		if (!dfn[i]) tarjan(i);
	
	for (int i = 1; i <= n; i++)
		for (int j = le[i]; j; j = e[j].nxt)
			if (in[i] != in[e[j].to])
				add_(in[i], in[e[j].to]);
	
	minnans = n + 1;
	for (int i = 1; i <= n; i++) {
		if (!ru[i]) {
			if (val[i] == -1) {//If there is no one you can catch in the point with penetration of 0, it means you can't catch all the people
				noans = 1;
				q.push(i);
				inn[i] = 1;
				minnans = min(minnans, minn[i]);
			}
			else {
				ans += val[i];
			}
		}
		if (val[i] != -1) {//This is for finding the first person who can't be caught by you (find those who can be caught by you)
			qq.push(i);
			inn[i] = -1;
		}
	}
	
	while (!qq.empty()) {//Run bfs and find all the points you can catch
		int now = qq.front();
		qq.pop();
		
		for (int i = le_[now]; i; i = e_[i].nxt)
			if (!inn[e_[i].to]) {
				inn[e_[i].to] = -1;
				qq.push(e_[i].to);
			}
	}
	while (!q.empty()) {//Run bfs and find all the points you can't catch
		int now = q.front();
		q.pop();
		
		for (int i = le_[now]; i; i = e_[i].nxt)
			if (!inn[e_[i].to]) {//This shows that if you meet someone who can be caught, you can't go down
				inn[e_[i].to] = 1;
				q.push(e_[i].to);
				minnans = min(minnans, minn[e_[i].to]);
			}
	}
	
	if (noans) {
		printf("NO\n");
		printf("%d", minnans);
	}
	else {
		printf("YES\n");
		printf("%d", ans);
	}
	
	return 0;
}

Topics: bfs tarjan