4016: 辉夜的夜空明珠

4016 4016 4016: 辉夜的夜空明珠
时间限制: 1.5 S e c 1.5 Sec 1.5Sec 内存限制: 512 M B 512 MB 512MB

题目描述
整个回廊可以看作一个 n n n 个点 m m m 条边的无向图,每条边走动花费的时间为 1 1 1。辉夜、永琳、铃仙、因幡帝等 k k k 个人或兔子可以通过传送阵分别进入这个图上的k 个特殊的点,然后去寻找闯入者。但是在寻找闯入者之前,他们要聚集到一个点,以增强战斗力。注意,可以先到的人停下不走等后来的人。

闯入者不知道回廊的规则,因此被困住,对辉夜等k 个人的行动没有影响。而辉夜等k个人必须按照回廊的规则走动。

回廊的规则如下:每个点有一个颜色,一共 4 4 4 种颜色,红、蓝、黄、绿,分别以 R 、 B 、 Y 、 G R、B、Y、G RBYG 表示。走动时必须在第 4 p + 1 4p+1 4p+1 步到 4 p + 4 4p+4 4p+4 步的时候走四种不同的颜色,当然最后一个不完整的周期内也不能走动相同颜色。注意,起点算第 1 1 1 步。

现在给定 k k k 个起点,辉夜想知道他们最短多长时间能够汇合,若不能汇合输出 − 1 -1 1

输入
第一行一个 C a s e Case Case,表示测试点编号。

第二行两个数 n n n m m m,表示图有 n n n 个点 m m m 条边。

第三行一个 k k k,表示有 k k k 个人。

第四行 k k k 个数,表示 k k k 个入口的编号。

第五行一个长度为 n n n 的字符串,仅包含 R B Y G RBYG RBYG,表示 n n n 个点的颜色。

下面 m m m 行每行两个数, u i , v i u_{i},v_{i} ui,vi,表示第 i i i 条边连接了 u i u_{i} ui v i v_{i} vi

输出
一个数表示最短汇合时间,不能汇合输出 − 1 -1 1

样例输入
1
5 4
4
1 2 3 4
RRRRG
1 5
2 5
3 5
4 5
样例输出
1

提示

数据范围
对于 100 % 100\% 100%的数据,保证 k ≥ 2 , n ≤ 50000 , m ≤ 200000 , k ≤ 10 k\geq2,n≤50000,m≤200000,k≤10 k2,n50000,m200000,k10

题解:
看到 k k k这么小。。。我就想到可能需要状压 k k k。。。
但事实上不需要。
求出从这 k k k个点出发,到每个点的最短路,并且带着颜色的状态跑。
b f s bfs bfs即可。
然后算出每个点到这 k k k个出发点的最大值的最小值即可。

#include<bits/stdc++.h>
using namespace std;
#define in inline
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define repd(i,a,b) for(int i=a;i>=b;i--)
#define For(i,a,b) for(int i=a;i<b;i++)
#define _(d) while(d(isdigit(ch=getchar())))
template<class T>in void g(T&t){T x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch-48;_()x=x*10+ch-48;t=f*x;}
const int N=5e4+3,M=200004;
struct E{
    int to,nxt;
}e[M<<1];
int head[N],tot,n,m,k,p[N],c[N];
in void ins(int x,int y){
    e[++tot]={y,head[x]};head[x]=tot;
}
typedef pair<int,int>P;
#define mk(a,b) make_pair(a,b)
#define fi first
#define se second
int d[15][17][N];int b[N],pp[N],inf;bool vis[N];
typedef long long ll;
in void spfa(int id,int st){
    queue<P>q;q.push(mk(st,1<<c[st]));
    d[id][1<<c[st]][st]=0;
    while(!q.empty()){
        P now=q.front();q.pop();
        int x=now.fi;//cout<<now.se<<endl;
        for(int i=head[x];i;i=e[i].nxt){
            //cout<<(now.se&(1<<c[e[i].to]))<<endl;
            if(now.se&(1<<c[e[i].to])){
                //puts("orzlkw");
                continue;
            } 
            int S=now.se|(1<<c[e[i].to]);S%=15;
            if(d[id][S][e[i].to]>d[id][now.se][x]+1){
                d[id][S][e[i].to]=d[id][now.se][x]+1;
                q.push(mk(e[i].to,S));
            }
        }
    }
}
char ch[N];
int main(){
    //freopen(".in","r",stdin);freopen(".out","w",stdout);
    g(n),g(n),g(m);
    g(k);rep(i,1,k) g(p[i]),pp[p[i]]=i;
    scanf("%s",ch+1);
    rep(i,1,n){
        if(ch[i]=='R') c[i]=0;
        if(ch[i]=='B') c[i]=1;
        if(ch[i]=='Y') c[i]=2;
        if(ch[i]=='G') c[i]=3;
    }
    memset(d,0x3f,sizeof(d)),inf=d[1][1][1];
    rep(i,1,m){
        int x,y;g(x),g(y);
        ins(x,y);ins(y,x);
    }
    rep(i,1,k) spfa(i,p[i]);
    int ans=inf;
    rep(i,1,n){
        int t1=0;
        rep(j,1,k){
            int tmp=inf;
            rep(l,0,16){
                tmp=min(tmp,d[j][l][i]);
            }
            //cout<<tmp<<endl;
            t1=max(t1,tmp);
            //cout<<t1<<endl;
        }
        ans=min(ans,t1);
    }
    printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可爱の小公举

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值