ZOJ 3811 Untrusted Patrol 标记+dfs

题意:(转自http://blog.csdn.net/qq574857122/article/details/39121391)

给定n个点m条边的无向图,k个触发器。

下面k个数表示触发器安装在哪几个点。

下面m行给出边

最后有l个信号,

给出信号发出的触发器的顺序。

每个触发器只会发出一次信号,且一个点只有一个触发器。

有一个人在遍历图。

每经过一个点,那个点的触发器就会发出信号,问是否存在一种走法使得这个人遍历了所有点且触发器发出的信号顺序和给出的一样。


题解:

这一题就是标记+搜索。

所有未访问的标记为d[i]=0, 未访问的信号灯标记为d[i]=1;

可以访问的标记为 d[i]=-1;

第一个信号灯入栈,并且dfs,对于普通灯,直接标记为-1且入栈,

对于信号灯(比如灯k)呢,也标记为-1但是 不入栈,(表示灯k随时可以访问,因为已走过得路可以重新走嘛)。

然后对于每个信号灯都判断当前是否已经访问到(是否为-1),是-》继续,否 输出No

哎,比赛的时候,边E[] 数组木有初始化。。 泪奔~~~~~~~

代码:

#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<stack>
#define MAXN 100000
typedef long long ll;
using namespace std;

int d[MAXN+5]; // 第i个pile是否被访问,1表示为信号灯,-1表示访问过
vector<int>E[MAXN+5];
int num[MAXN+5][2];
stack<int>Q;
int fa[MAXN+5];
/*
int getfather(int x)
{
    if(fa[x]==-1) return x;
    else return fa[x]=getfather(fa[x]);
}

void merge(int x,int y)
{
    x=getfather(x);
    y=getfather(y);
    if(x==y) return;
    if(x<y) fa[y]=x;
    else fa[x]=y;
}
*/
int main()
{
    int n,m,k,l;
    int T,ok;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&k);

        memset(d,0,sizeof(d));
        memset(fa,-1,sizeof(fa));
        for(int i=1;i<=n;i++) E[i].clear();  // 没有初始化,导致无限WA

        for(int i=1;i<=k;i++)
            {
                scanf("%d",&num[i][0]);
                d[num[i][0]]=1;
            }
        for(int i=1;i<=m;i++)
        {
            int from,to;
            scanf("%d%d",&from,&to);
            E[from].push_back(to);
            E[to].push_back(from);
        //    merge(from,to);
        }
      /*  int flag=0;
        for(int i=1;i<=n;i++)
            if(fa[i]==-1) flag++;
     //   printf("flag=%d\n",flag);
        flag=flag==1?1:0; */

        scanf("%d",&l);
        for(int i=1;i<=l;i++)
                scanf("%d",&num[i][1]);

        if(l<k) puts("No");
        else{
            ok=1;
            num[l+1][1]=n+1;
            d[n+1]=-1;
            for(int i=1;i<=l;i++)
            {
                int now=num[i][1];
                int nx=num[i+1][1];
                d[num[i][1]]=-1;
                while(!Q.empty())  Q.pop();
                Q.push(now);

                while(!Q.empty()){
                    int x=Q.top();
                    Q.pop();
                    for(int i=0;i<E[x].size();i++)
                    {
                        int indx=E[x][i];

                        if(d[indx]==1) //未访问的信号灯
                            d[indx]=-1;// 变为已访问,但是不入栈
                        else if(!d[indx]) //普通灯
                              {
                                  Q.push(indx);//变为已访问,且入栈
                                  d[indx]=-1;
                              }
                    }
                }

                if(d[nx]!=-1) { ok=0; break; }
            }


            for(int i=1;i<=n;i++)
                if(!d[i]) {ok=0; break;}

            if(ok ) puts("Yes");
            else puts("No");
        }
    }

    return 0;
}

还有一种 用星状链表做的:

复习一下~


#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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值