2020/10/23 模拟赛 escape

Description

小恩听说有人想在邻国放置SD反导系统十分不满,为了做好应对导弹战的准备,小恩进行 了新的军队部署。 小恩的国家有 $n$个城市 $m$条无向道路,每条边长度都是正值。现在小恩想从$1$号城市向$n$ 号城市转移部分军队。由于这支部队已经多次执行了从$1$号城市到$n$号城市转移的任务,他们 己经走过了所有从$1$号到$n$号所有可能的最短路。为了迷惑敌国,小恩决定走剩下的路径中最 短的那一条简单路径,但又为了照顾到士兵的情绪,小恩要求这条路径如果经过了某些之前进行 从$1$到$n$的最短路转移时走过的道路,则这些道路必须按照原来的方向前进。现在问满足条件 的道路最短是多少。

Solution

图中要求一条有限制的次短路的长度

有一个二进制分组的非正解方法

给每一个点分配编号,设定集合$A_1,A_2, \cdots ,A_{18}$,集合$B_1,B_2, \cdots , B_{18}$,$A$集合表示在最短路上的编号第$i$位为0的点,$B$集合表示在最短路上的编号第$i$位为1的点

如此操作可以使任意一对点至少在一种情况下分属$A$、$B$两个集合

所以可以由$A$向$B$跑最短路,不经由最短路上的边,再由$B$向$A$重复一边

只加入在最短路上的点是因为题目要求简单路径,若不如此可能会出现路径重叠

实际上跑上几次正确率就已经非常高了,所以可以卡时

2020/10/23 模拟赛 escape
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<ctime>
using namespace std;
long long n,m,tot=1,head[100005],dist[100005],sdis[100005],tdis[100005],que[100005],top,A[100005],a,B[100005],b,ans=1<<30,len;
bool vst[100005],ban[2000005],tag[100005];
struct Edge
{
    long long to,nxt,w,sta;
}edge[2000005];
queue<long long>q;
inline long long read()
{
    long long f=1,w=0;
    char ch=0;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        w=(w<<1)+(w<<3)+ch-'0';
        ch=getchar();
    }
    return f*w;
}
void SPFA()
{
    while(q.size())
    {
        long long u=q.front();
        q.pop();
        vst[u]=false;
        for(long long i=head[u];i;i=edge[i].nxt)
        {
            if(ban[i])
            {
                continue;
            }
            long long v=edge[i].to;
            if(dist[v]>dist[u]+edge[i].w)
            {
                dist[v]=dist[u]+edge[i].w;
                if(!vst[v])
                {
                    q.push(v);
                    vst[v]=true;
                }
            }
        }
    }
}
int main()
{
    n=read();
    m=read();
    for(long long i=1;i<=m;i++)
    {
        long long x=read(),y=read(),u=read();
        edge[++tot]=(Edge){y,head[x],u,x};
        head[x]=tot;
        edge[++tot]=(Edge){x,head[y],u,y};
        head[y]=tot;
    }
    memset(dist,127,sizeof(dist));
    q.push(1);
    vst[1]=true;
    dist[1]=0;
    SPFA();
    for(long long i=1;i<=n;i++)
    {
        sdis[i]=dist[i];
    }
    len=dist[n];
    memset(dist,127,sizeof(dist));
    q.push(n);
    vst[n]=true;
    dist[n]=0;
    SPFA();
    for(long long i=1;i<=n;i++)
    {
        tdis[i]=dist[i];
    }
    for(long long i=2;i<=tot;i++)
    {
        if(sdis[edge[i].sta]+edge[i].w+tdis[edge[i].to]==len)
        {
            if(!tag[edge[i].sta])
            {
                que[++top]=edge[i].sta;
            }
            if(!tag[edge[i].to])
            {
                que[++top]=edge[i].to;
            }
            tag[edge[i].sta]=tag[edge[i].to]=ban[i]=ban[i^1]=true;
        }
    }
    for(long long i=0;i<=17;i++)
    {
        a=b=0;
        for(long long j=1;j<=top;j++)
        {
            if(que[j]&(1<<i))
            {
                A[++a]=que[j];
            }
            else
            {
                B[++b]=que[j];
            }
        }
        memset(dist,127,sizeof(dist));
        for(long long j=1;j<=a;j++)
        {
            dist[A[j]]=sdis[A[j]];
            q.push(A[j]);
            vst[A[j]]=true;
        }
        SPFA();
        for(long long j=1;j<=b;j++)
        {
            ans=min(ans,dist[B[j]]+tdis[B[j]]);
        }
        swap(a,b);
        swap(A,B);
        memset(dist,127,sizeof(dist));
        for(long long j=1;j<=a;j++)
        {
            dist[A[j]]=sdis[A[j]];
            q.push(A[j]);
            vst[A[j]]=true;
        }
        SPFA();
        for(long long j=1;j<=b;j++)
        {
            ans=min(ans,dist[B[j]]+tdis[B[j]]);
        }
        if(clock()>1.5*CLOCKS_PER_SEC)
        {
            break;
        }
    }
    printf("%lld\n",ans);
    return 0;
}
escape

 

上一篇:严格次小生成树


下一篇:Unity StateMachineBehaviour