zoj 3811 Untrusted Patrol (按照顺序访问点+并查集||宽搜)

6 篇文章 0 订阅
5 篇文章 0 订阅

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3811

题意:

有n个点,其中有k个点是有摄像头的,然后会给出L个有序的点,要求按照顺序访问(后面没有被访问过的有摄像头的点,不能走)。

并查集:

首先遍历整张图,要将所有的无关点(没有摄像头的点),相同的合并到一个集合里面,然后在将有关点一个一个的合并进去,要是有不在一个集合的,那么就是走不通的

用vector的版本(最开始vector一直没有清空,导致wrong了很多次)

#include<stdio.h>
#include<string.h>
#include<vector>

#define mt(a,b) memset(a,b,sizeof(a))
#define MAX 100009
using namespace std;
int point[MAX],seq[MAX];
bool mark[MAX];
vector <int> vec[MAX];
struct Node {
    int s;
    int e;
} edge[MAX*2];
struct Ele {
    int parent;
    int num;
} elem[MAX];
void make_set(int n) {
    for(int i=1; i<=n; i++) {
        elem[i].parent=i;
        elem[i].num=1;
    }
}
int Find(int x) {
    int root,temp;
    temp=x;
    while(x!=elem[x].parent)    //寻找根节点
        x=elem[x].parent;
    root=x;
    x=temp;
    while (x!=elem[x].parent) {//压缩路径,全部赋值为根节点的值
        temp=elem[x].parent;
        elem[x].parent=root;
        x=temp;
    }
    return root;
}
void Union(int a,int b) { //合并两个集合
    int x,y;
    x=Find(a);
    y=Find(b);
    if(elem[x].num>=elem[y].num) {
        elem[y].parent=elem[x].parent;
        elem[x].num+=elem[y].num;
    } else {
        elem[x].parent=elem[y].parent;
        elem[y].num+=elem[x].num;
    }
}
int main() {
    int T,n,m,k,L;
    scanf("%d",&T);
    while(T--) {
        memset(mark,false,sizeof(mark));
        scanf("%d %d %d",&n,&m,&k);
        for(int i=0; i<k; i++) {
            scanf("%d",&point[i]);
            mark[point[i]]=true;
        }
        for(int i=0;i<=n;i++) vec[i].clear();
        for(int i=0; i<m; i++) {
            scanf("%d %d",&edge[i].s,&edge[i].e);
            vec[edge[i].s].push_back(edge[i].e);
            vec[edge[i].e].push_back(edge[i].s);
        }
        scanf("%d",&L);
        for(int i=0; i<L; i++) {
            scanf("%d",&seq[i]);
        }
        if(L!=k) {
            printf("No\n");
            continue;
        }
        make_set(n);
        int len;
        bool flag=false;
        mark[seq[0]]=false;
        for(int i=1;i<=n;i++){
            if(mark[i]==false){
                len=vec[i].size();
                for(int j=0;j<len;j++){
                    if(mark[vec[i][j]]==false){
                        Union(i,vec[i][j]);
                    }
                }
            }
        }
        len=vec[seq[0]].size();
        for(int i=0; i<len; i++) {
            if(mark[vec[seq[0]][i]]==false)
                Union(seq[0],vec[seq[0]][i]);
        }
        for(int i=1; i<L; i++) {
            mark[seq[i]]=false;
            len=vec[seq[i]].size();
            for(int j=0; j<len; j++) {
                if(mark[vec[seq[i]][j]]==false) {
                    Union(seq[i],vec[seq[i]][j]);
                }
            }
            int fa = Find(seq[i-1]);
            int fb = Find(seq[i]);
            if(fa!=fb) {
                flag=true;
                break;
            }
        }
        bool flag1=false;
        int fa=Find(1);
        for(int i=2; i<=n; i++) {
            int fb=Find(i);
            if(fa!=fb) {
                flag1=true;
                break;
            }
        }
        if(flag==false&&flag1==false) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

宽搜:

按照顺序,从每个有摄像头的地方顺次的搜索,直到不能扩展为止,那么当第seq[i]这个点扩展完整为止,要是seq[i+1]这个没有被扩展到,那么一定不能完成任务了。

#include<stdio.h>
#include<string.h>
#include<vector>
#include<queue>
#define MAX 100009
using namespace std;
vector <int> vec[MAX];
bool mark[MAX];//用于标记是否有路灯
bool used[MAX];//标记找一对顶点的过程中的点,是否被访问过
struct Node{
    int s;
    int e;
}edge[2*MAX];
int point[MAX],seq[MAX];
void deal(int f) {
    queue<int>Que;
    while(!Que.empty()) Que.pop();
    Que.push(f);
    used[f]=true;
    mark[f]=false;
    while(!Que.empty()) {
        int tmp=Que.front();
        Que.pop();
        //printf("~~%d\n",tmp);
        if(mark[tmp]==false) {
            int len=vec[tmp].size();
            for(int i=0; i<len; i++) {
                if(used[vec[tmp][i]]==false) {
                    Que.push(vec[tmp][i]);
                    used[vec[tmp][i]]=true;
                }
            }
        }
    }
}
int main() {
    int T,n,m,k,L;
    scanf("%d",&T);
    while(T--) {
        scanf("%d %d %d",&n,&m,&k);
        memset(mark,false,sizeof(mark));
        for(int i=0;i<=n;i++) vec[i].clear();
        for(int i=0; i<k; i++) {
            scanf("%d",&point[i]);
            mark[point[i]]=true;
        }
        for(int i=0; i<m; i++) {
            scanf("%d %d",&edge[i].s,&edge[i].e);
            vec[edge[i].s].push_back(edge[i].e);
            vec[edge[i].e].push_back(edge[i].s);
        }
        scanf("%d",&L);
        for(int i=0; i<L; i++) {
            scanf("%d",&seq[i]);
        }
        if(L!=k) {
            printf("No\n");
            continue;
        }
        int i;
        memset(used,false,sizeof(used));
        deal(seq[0]);
        for(i=1; i<L; i++) {
            if(used[seq[i]]==false) break;
            deal(seq[i]);
        }
        bool num=false;
        for(int j=1;j<=n;j++){
            if(used[j]==false) {
                num=true;
                break;
            }
        }
        if(i==L&&num==false) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值