zoukankan      html  css  js  c++  java
  • 洛谷题单-【图论】省选图论

    链接:https://www.luogu.com.cn/training/2965#information

    P3758 [TJOI2017]可乐(图论DP)

    题意:

    给一张无向图,先在从点$1$出发,每次可以有$3$种选择,可以原地不动,可以选择爆炸(即直接结束),还可以选择向其他点移动,问总的移动方案数

    思路:

    很有意思的一道图论$DP$,自己做的时候用$2e8$的复杂度开着$O2$卡过去了,没开的话只能过最后两个点

    最开始想的是个搜索的方法,直接给$T$傻了,随便一测当$t=30$的时候就出不来了

    之后就想了个$DP$,定义$DP[i][j]$为经过前$i$秒到$j$的方案数,但是这样会漏掉自己爆炸的方案,正确的做法应该是一个新的点$n=0$,就代表着爆炸,并将所有点连向它

    转态转移方程也很简单$DP[i][j]=sum dp[i-1][j],j$为与$i$连接的点,注意还有自己也可以连向自己

    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<cstdio>
    typedef long long ll;
     using namespace std;
     const int maxn=1e6+10;
     const int mod=2017;
     vector<int> a[31];
     ll n,m,t,ans=0,dp[31][2],pos,last;
     int main()
     {
         scanf("%lld%lld",&n,&m);
         for(int i=1;i<=m;i++){
             int u,v;
             scanf("%d%d",&u,&v);
             a[u].push_back(v);
             a[v].push_back(u);
         }
        scanf("%lld",&t);
        dp[1][0]=1;
        pos=1;
        for(int i=1;i<=t;i++){
            last=pos^1;
            for(int j=1;j<=n;j++) dp[j][pos]=0;
            for(int j=1;j<=n;j++){
                ans=(ans+dp[j][last])%mod;
                dp[j][pos]=(dp[j][pos]+dp[j][last])%mod;
                for(int k=0;k<a[j].size();k++){
                    int v=a[j][k];
                    dp[j][pos]=(dp[j][pos]+dp[v][last])%mod;
                }
                if(i==t){
                    ans=(ans+dp[j][pos])%mod;
                } 
            }
            pos^=1;
        }
        printf("%lld",ans%mod);
        return 0;
      } 
    View Code

    看完题解后,发现了更为简单的方法,定义$A$为图的邻接矩阵,那么$A^{k}$的矩阵中第$i$行第$j$列的意义就为经过$k$秒后从$i$到$j$的方案数

    爆炸与原地不动的处理方法与我之前说的基本一致,就是新建一个节点与连上自环即可,最后答案就为$sum_{i=0}^{n} A[1][i]$

    至于为什么邻接矩阵有这个含义,我们可以看看矩阵乘法的含义,相乘过后的矩阵$A[i][j]=sum_{k=1}^{n}A[i][k]*A[k][j]$可以认为$k$为中间点,从$i$到$j$的方案数就为从$i$到不同中间节点再到$j$的方案数的总和,这样就能很好的解释了

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    typedef long long ll;
    typedef unsigned long long ull;
    using namespace std;
    const int P=2017;
    struct Matrix{
        int a[31][31];
        inline Matrix operator * (const Matrix &rhs)
        {
            Matrix ret;
            memset(&ret,0,sizeof ret);
            for(int i=0;i<=30;i++)
                for(int j=0;j<=30;j++)
                    for(int k=0;k<=30;k++)
                        (ret.a[i][j]+=a[i][k]*rhs.a[k][j]%P)%=P;
            return ret;
        }
    }mp;
    Matrix ksm(Matrix &a,int b)
    {
        Matrix ret;
        memset(&ret,0,sizeof ret);
        for(int i=0;i<=30;i++) ret.a[i][i]=1;
        while(b)
        {
            if(b&1) ret=ret*a;
            a=a*a;b>>=1;
        }
        return ret;
    }
    int u,v,n,m,t;
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            mp.a[u][v]=1;mp.a[v][u]=1;
        }
        for(int i=0;i<=n;i++)
            mp.a[i][i]=1;
        for(int i=1;i<=n;i++) mp.a[i][0]=1;
        int ans=0;
        scanf("%d",&t);
        Matrix anss=ksm(mp,t);
        for(int i=0;i<=n;i++) (ans+=anss.a[1][i])%=P;
        printf("%d
    ",ans);
    }
    View Code
  • 相关阅读:
    装机常用
    配置Linux服务器TensorFlow环境的问题汇总
    pycharm在C盘创建.pycharm2019.3严重占用内存的解决方法
    更新2020-02-29 --ECCV2018 Burst image deblurring using permutation invariant cnn
    代码解读 Aittala_ECCV18_Burst Image Deblurring Using Permutation Invariant Convolutional Neural Networks
    深度学习基础知识
    Image Alignment Toolbox
    Matlab安装编译器
    Aurora Equation在word中出现latex Problem Running的解决
    model中的一些处理
  • 原文地址:https://www.cnblogs.com/overrate-wsj/p/12726557.html
Copyright © 2011-2022 走看看