ZOJ 3644 Kitty's Game dfs,记忆化搜索,map映射 难度:2

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4834

从点1出发,假设现在在i,点数为sta,则下一步的点数必然不能是sta的因数,所以不会形成环,只需从1直接走,走到n即可.

但是如果这样的话时空复杂度就都是nk,明显不满足题意,而这个时候我们可以想到,每个状态都必然是k的约数,(点数不是k的约数的节点不在路上,可以无视),而约数的个数也就k^0.5个,可以直接用map映射,这样时空复杂度都是n*k^0.5,可以解出答案.

一开始直接用dfs,结果TLE了.

#include <cstdio>
#include <cstring>
#include <map>
using namespace std;
const int maxn = 2001;
const int maxm = 2e4+4;
const int mod = 1000000007;
const int maxk = 1e6+6;
int n,m,k;
int p[maxn];
typedef long long ll;
map<int ,int >id;
ll dp[maxn][maxn];
int first[maxn];
struct edge{
    int nxt,t;
}e[maxm];
void addedge(int f,int t,int ind){
    e[ind].nxt = first[f];
    e[ind].t = t;
    first[f] = ind;
}
int bit[30],num;
void apart(int k){
    for(int i=2;i*i<=k;i++){
        while(k%i==0){
            bit[num++]=i;
            k/=i;
        }
    }
    if(k>1)bit[num++]=k;
}
ll gcd(ll a,ll b){
    if(b==0)return a;
    return gcd(b,a%b);
}
ll lcm(ll a,ll b){
    return a*b/gcd(a,b);
}
bool vis[maxn];
int cnt;
ll dfs(int s,int sav){
    if(id[sav]!=0&&dp[s][id[sav]]!=0)return dp[s][id[sav]];
    if(s==n)return sav==k?1:0;
    vis[s]=true;
    if(id[sav]==0)id[sav]=++cnt;
    for(int pe=first[s];pe!=-1;pe=e[pe].nxt){
        int t=e[pe].t;
        ll lcmnum=lcm(p[t],sav);
        if(vis[t]||lcmnum==sav||lcmnum>k)continue;
        dp[s][id[sav]]+=dfs(t,lcmnum);
        dp[s][id[sav]]%=mod;
    }
    vis[s]=false;
    return dp[s][id[sav]];
}
int solve(){
    num=0;
    apart(k);
    if(lcm(p[1],k)!=k||lcm(p[n],k)!=k)return 0;
    for(int i=2;i<n;i++){
        if(lcm(p[i],k)!=k){
            vis[i]=true;
        }
    }
    return dfs(1,p[1]);
}

void init(){
    memset(first,-1,sizeof first);
    memset(dp,0,sizeof dp);
    memset(vis,0,sizeof vis);
    cnt=0;
    id.clear();
}
int main(){
    while(scanf("%d%d%d",&n,&m,&k)==3){
        init();
        for(int i = 0;i < m;i++){
            int f,t;
            scanf("%d%d",&f,&t);
            addedge(f,t,i);
        }
        for(int i = 1;i <= n;i++){
            scanf("%d",p+i);
        }
        int ans=solve();
        printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/xuesu/p/4509014.html