zoukankan      html  css  js  c++  java
  • 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加了点东西。

  • 相关阅读:
    ionic localstorage
    angular 中文鏈接
    把jqmobi 變成jQuery 的插件 從此使用jQuery
    jqmobi 的一些設置
    ionic ngcordova map 地圖
    ionic pull to refresh 下拉更新頁面
    json 對象的序列化
    鍵盤彈出,頁面佈局被推上去了.....
    Cordova V3.0.0中config.xml配置文件的iOS Configuration
    android ios 只能輸入數字 不能輸入小數點的 函數 cordova
  • 原文地址:https://www.cnblogs.com/TheRoadToAu/p/7859021.html
Copyright © 2011-2022 走看看