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
  • 相关阅读:
    奇数阶魔方问题
    《DSP using MATLAB》示例9.3
    《DSP using MATLAB》示例9.2
    《DSP using MATLAB》示例9.1
    找个目标很重要
    《DSP using MATLAB》示例Example 8.30
    《DSP using MATLAB》示例Example 8.29
    《DSP using MATLAB》示例Example 8.28
    《DSP using MATLAB》示例Example 8.27
    《DSP using MATLAB》示例Example 8.26
  • 原文地址:https://www.cnblogs.com/overrate-wsj/p/12726557.html
Copyright © 2011-2022 走看看