• NOIp知识点复习——最短路计数


    $Mingqi\_H$

    NOIp 2017考挂了...gg

    重新开始好了。

    计划明年2月24号前复习完所有的NOIp知识点(毕竟很不熟练啊),之后到七月底前学习完省选的东西(flag?)。

    从现在开始吧。

    11.29 NOIp图论(Ⅰ)

    坑:Floyd、Dijkstra、最短路计数、Tarjan、二分图、拓扑。

    最短路计数:

    类似一个标准的SPFA,不同之处在于加粗的两句:

    • 如果第一次到达nxt节点,nxt节点的最短路数量就等于其前驱节点的最短路数量,当前点需要松弛,则当前点继承被松弛节点的最短路条数,更新一波距离,丢到队列里。
    • 否则当到nxt的最短路长度等于到其前驱点的最短路+当前边的权值时,到nxt点的最短路数量应该加上到其前驱节点的最短路数量(再次更新)。

    例题:洛谷P1144,P1608,P3953前30%。

    #include<queue>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn=1e5+10;
    struct Edge{int u,v,w;}edge[2*maxn];int head[maxn],cnt;
    void add(int u,int v,int w){edge[++cnt].u=head[u],edge[cnt].v=v,edge[cnt].w=w,head[u]=cnt;}
    int dis[maxn],vis[maxn];
    int ans[maxn];
    inline void spfa(int s)
    {
        queue<int>q;int cur,nxt;
        memset(dis,0x7f,sizeof(dis)),memset(vis,0,sizeof(vis));
        dis[s]=0,vis[s]=1,q.push(s);
        ans[s]=1;
        while(!q.empty())
        {
            cur=q.front(),vis[cur]=0,q.pop();
            for(int i=head[cur];i;i=edge[i].u)
            {
                nxt=edge[i].v;
                if(!ans[nxt])ans[nxt]=ans[cur],dis[nxt]=dis[cur]+edge[i].w,q.push(nxt);
                else if(dis[nxt]==dis[cur]+edge[i].w)ans[nxt]+=ans[cur],ans[nxt]%=mod;
            }
        }
    }
    View Code

     以上代码似乎是错误的。gg。

    P1608

    #include<cstdio>
    #include<queue>
    #include<cstring>
    using namespace std;
    const int N = 2200;
    int head[N];
    struct node{
        int v,w,next;
    }edge[N*N/2];
    int n,e,num=0,dis[N];bool vis[N];
    void add_edge(int x,int y,int z)
    {
        edge[++num].v=y;edge[num].w=z;edge[num].next=head[x];head[x]=num;
    }
    int ans1,cnt[N];
    int minn=0;
    void spfa(int x)
    {
        queue<int>que;
        vis[1]=1;dis[1]=0;cnt[1]=1;
        que.push(1);
        while(!que.empty())
        {
            int u=que.front();que.pop();
            if(u==n)continue;
            for(int i=head[u];i;i=edge[i].next)
            {
                int v=edge[i].v;
                if(dis[u]+edge[i].w<dis[v])
                {
                    if(dis[u]+edge[i].w<dis[v])
                    {
                        dis[v]=dis[x]+edge[i].w;
                        cnt[v]=cnt[u];
                    }
                    if(!vis[v])que.push(v),vis[v]=1;
                }
                else if(dis[u]+edge[i].w==dis[v]) cnt[v]+=cnt[u];
            }
            vis[u]=0;cnt[u]=0;
        }
    }
    int main()
    {
        memset(dis,0x3f,sizeof dis);
        scanf("%d%d",&n,&e);
        int a,b,c;
        for(int i=1;i<=e;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            add_edge(a,b,c);
        }
        spfa(1);
        if(dis[n]==0x3f3f3f3f)
            puts("No Answer");
        else printf("%d %d
    ",dis[n],cnt[n]);
        return 0;
    }
    View Code

     啊...原来是题目有锅。。。代码没什么问题。

    P3953前30%:

    #include<queue>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn=100000+10;
    struct Edge{int u,v,w;} edge[2*maxn];
    int head[maxn],c;
    void add(int u,int v,int w){edge[++c].u=head[u],edge[c].v=v,edge[c].w=w,head[u]=c;}
    int n,m,x,y,z,k,p,t;
    int dis[maxn],cnt[maxn],vis[maxn];
    int cur,v;
    void spfa(int s)
    {
        memset(dis,0x3f,sizeof(dis)),memset(cnt,0,sizeof(cnt)),memset(vis,0,sizeof(vis));
        queue<int>q;
        q.push(s),dis[s]=0,cnt[s]=1;
        while(!q.empty())
        {
            cur=q.front(),q.pop(),vis[cur]=0;
            if(cur==n)continue;
            for(int i=head[cur]; i; i=edge[i].u)
            {
                v=edge[i].v;
                if(dis[cur]+edge[i].w==dis[v])cnt[v]=(cnt[v]+cnt[i])%p;
                if(dis[cur]+edge[i].w<dis[v])dis[v]=dis[cur]+edge[i].w,cnt[v]=cnt[cur];
                if(cnt[v]&&!vis[v])vis[v]=1,q.push(v);
            }
            cnt[cur]=0;
        }
    }
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            memset(head,0,sizeof(head)),c=0,memset(edge,0,sizeof(edge));
            scanf("%d%d%d%d",&n,&m,&k,&p);
            while(m--)scanf("%d%d%d",&x,&y,&z),add(x,y,z);
            spfa(1);
            printf("%d
    ",cnt[n]);
        }
        return 0;
    }
    View Code

    由此我们可以得到一般的最短路计数的模板。

    void spfa(int s)
    {
        memset(dis,0x3f,sizeof(dis)),memset(cnt,0,sizeof(cnt)),memset(vis,0,sizeof(vis));
        queue<int>q;
        q.push(s),dis[s]=0,cnt[s]=1;
        while(!q.empty())
        {
            cur=q.front(),q.pop(),vis[cur]=0;
            if(cur==n)continue;
           for(int i=head[cur]; i; i=edge[i].u)
            {
                v=edge[i].v;
                if(dis[cur]+edge[i].w==dis[v])cnt[v]+=cnt[i];
                if(dis[cur]+edge[i].w<dis[v])dis[v]=dis[cur]+edge[i].w,cnt[v]=cnt[cur];
                if(cnt[v]&&!vis[v])vis[v]=1,q.push(v);
            }
            cnt[cur]=0;
        }
    }

    就是一个普通SPFA加了点东西。

  • 相关阅读:
    vim lua对齐indent无效
    C中的私有成员
    Lua 设置table为只读属性
    c语言结构体可以直接赋值
    Lua5.3 注册表 _G _ENV
    火狐浏览器调试ajax异步页面时报错NS_ERROR_UNEXPECTER
    ajax向后台请求数据,后台接收到数据并进行了处理,但前台就是调用error方法
    maven安装之后,或者升级之后遇到的问题:could not find or load main class org.codehaus.plexus.class.....
    jenkins执行shell命令,有时会提示“Command not found”
    shell 脚本替换文件中某个字符串
  • 原文地址:https://www.cnblogs.com/TheRoadToAu/p/7859021.html
Copyright © 2020-2023  润新知