GYM 101615 G - Security Badge

博客给出Codeforces题目G的链接,介绍两种题解。题解1用spfa更新集合,将输入数据离散化,用布尔数组表示集合;题解2是离散后用dfs验证边界值合法性,还给出了对应代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接

http://codeforces.com/gym/101615/problem/G

题解1

打比赛的时候自己瞎 yy y y 了一个做法,就是每个点 s s 记录一个集合S[x],表示哪些数能走到这里,初始点是 1...k 1... k ,我用 spfa s p f a 来更新,比方说我用 u u 去更新v,边上的集合是 s s ,那就S[u]sS[v] S[v]
箭头表示更新
不用真的存 1...k 1... k ,最后的集合的边界肯定是输入的某条边的某个上下界,我把输入数据离散化,然后开一个 M M 级别大小的布尔数组表示集合中这个数字是否存在就行了

代码1

#include <bits/stdc++.h>
#define maxn 1010
#define maxm 5010
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
struct Set
{
    bool v[maxm<<1];
    Set(){cl(v);}
}d[maxn], e[maxm];
int head[maxn], to[maxm], nex[maxm], l[maxm], r[maxm], S, dest, N, M, tmp[maxm<<1], tot, K, T, vis[maxn];
void adde(int a, int b, int v1, int v2){to[++tot]=b;l[tot]=v1;r[tot]=v2;nex[tot]=head[a];head[a]=tot;}
Set bing(Set &a, Set &b)
{
    int i;
    Set ans;
    for(i=1;i<=T;i++)ans.v[i]=a.v[i] or b.v[i];
    return ans;
}
Set jiao(Set &a, Set &b)
{
    int i;
    Set ans;
    for(i=1;i<=T;i++)ans.v[i]=a.v[i] and b.v[i];
    return ans;
}
int read(int x=0)
{
    int f=1, c;
    for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-48;
    return f*x;
}
void ls(int &x){x=lower_bound(tmp+1,tmp+T+1,x)-tmp;}
void init()
{
    int i, u, v, a, b, x=0, j;
    N=read(), M=read(), K=read();
    S=read(), dest=read();
    for(i=1;i<=M;i++)
    {
        u=read(), v=read(), a=read(), b=read();
        adde(u,v,a,b);
        tmp[++T]=a-1, tmp[++T]=b;
    }
    tmp[++T]=K;
    sort(tmp+1,tmp+T+1);
    for(i=1;i<=T;i++)if(tmp[i]!=tmp[i-1])tmp[++x]=tmp[i];T=x;
    for(i=1;i<=tot;i++)ls(l[i]), ls(r[i]);
    for(i=1;i<=tot;i++)for(j=l[i];j<=r[i];j++)e[i].v[j]=1;
}
bool in(Set &a, Set &b)
{
    int i;
    for(i=1;i<=T;i++)if(a.v[i]==1 and b.v[i]==0)return false;
    return true;
}
void spfa()
{
    Set s;
    int i, now, p;
    queue<int> q;
    for(i=1;i<=T;i++)d[S].v[i]=1;
    q.push(S);
    while(!q.empty())
    {
        now=q.front(); q.pop();
        vis[now]=0;
        for(p=head[now];p;p=nex[p])
        {
            s=jiao(d[now],e[p]);
            if(!in(s,d[to[p]]))
            {
                d[to[p]]=bing(s,d[to[p]]);
                if(!vis[to[p]])vis[to[p]]=1, q.push(to[p]);
            }
        }
    }
}
void show()
{
    int i, ans=0, j;
    for(i=1;i<=T;i++)
    {
        if(d[dest].v[i]==1)
        {
            ans+=tmp[i]-tmp[i-1];
        }
    }
    printf("%d",ans);
}
int main()
{
    init();
    spfa();
    show();
    return 0;
}

题解2

大家好像都不是我上面那种脑洞做法,听过了这道题的人说,离散之后直接用dfs验证下那些边界值是否合法就行了
我:……

代码2

#include <bits/stdc++.h>
#define maxn 1010
#define maxm 5010
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
int head[maxn], to[maxm], nex[maxm], l[maxm], r[maxm], S, dest, N, M, tmp[maxm<<2], tot, K, T, vis[maxn], ok[maxm<<2];
void adde(int a, int b, int v1, int v2){to[++tot]=b;l[tot]=v1;r[tot]=v2;nex[tot]=head[a];head[a]=tot;}
int dfs(int pos, int k)
{
    int p;
    vis[pos]=1;
    for(p=head[pos];p;p=nex[p])
        if(!vis[to[p]] and k>=l[p] and k<=r[p])dfs(to[p],k);
}
int read(int x=0)
{
    int f=1, c;
    for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-48;
    return f*x;
}
void ls(int &x){x=lower_bound(tmp+1,tmp+T+1,x)-tmp;}
void init()
{
    int i, u, v, a, b, x=0, j;
    N=read(), M=read(), K=read();
    S=read(), dest=read();
    for(i=1;i<=M;i++)
    {
        u=read(), v=read(), a=read(), b=read();
        adde(u,v,a,b);
        tmp[++T]=a-1, tmp[++T]=b;
    }
    sort(tmp+1,tmp+T+1);
}
int main()
{
    int i, ans=0;
    init();
    for(i=1;i<=T;i++)
    {
        cl(vis);
        dfs(S,tmp[i]);
        if(vis[dest])ans+=tmp[i]-tmp[i-1];
    }
    printf("%d",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值