ZOJ 3811 Untrusted Patrol

题意:

一幅图某些点有监视器  监视器只记录第一次路过的时间  问  给出路线序列  是否存在满足序列的情况下遍历整幅图的点

思路:

不要想割点  割点无法处理在一个双连通分量内的多个监视器  这题就是贪心+搜索

贪心就是尽量多的使用不违背序列的点  那么我们先把序列里的第一个点和不存在监视器的点加入图  并将他们连边  对于其他的序列中的点  如果这个点存在与第一个点所形成的连通块连接的边  那么就加入这个点  否则没有答案

这里的加入点其实就是一个染色的过程  所以用搜索来搞一下

代码:

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<vector>
using namespace std;
typedef long long LL;
#define N 100010
#define M 400010
#define inf 2147483647

int n, m, Q, q, tot, ans;
int order[N], have[N], vis[N], head[N];
struct edge {
	int u, v, next;
	bool flag;
} ed[M];

void init() {
	tot = 0;
	ans = 1;
	memset(have, 0, sizeof(have));
	memset(vis, 0, sizeof(vis));
	memset(head, -1, sizeof(head));
}

void add(int u, int v) {
	ed[tot].u = u;
	ed[tot].v = v;
	ed[tot].flag = false;
	ed[tot].next = head[u];
	head[u] = tot++;
}

void dfs(int u) {
	vis[u] = 1;
	for (int i = head[u]; ~i; i = ed[i].next) {
		int v = ed[i].v;
		if (!vis[v] && !have[v])
			dfs(v);
	}
}

int main() {
	int cas, i, u, v;
	scanf("%d", &cas);
	while (cas--) {
		init();
		scanf("%d%d%d", &n, &m, &Q);
		for (i = 1; i <= Q; i++) {
			scanf("%d", &u);
			have[u] = 1;
		}
		for (i = 1; i <= m; i++) {
			scanf("%d%d", &u, &v);
			add(u, v);
			add(v, u);
		}
		scanf("%d", &q);
		for (i = 1; i <= q; i++)
			scanf("%d", &order[i]);
		if (Q != q)
			ans = 0;
		dfs(order[1]);
		for (i = 2; i <= q; i++) {
			v = 0;
			for (u = head[order[i]]; ~u; u = ed[u].next) {
				if (vis[ed[u].v]) {
					v = 1;
					break;
				}
			}
			if (!v) {
				ans = 0;
				break;
			}
			dfs(order[i]);
		}
		for (i = 1; i <= n; i++) {
			if (!vis[i]) {
				ans = 0;
				break;
			}
		}
		if (ans)
			printf("Yes\n");
		else
			printf("No\n");
	}
	return 0;
}


你可能感兴趣的:(搜索,ZOJ,贪心)