记忆化搜索建图方法优化

发布时间 2023-08-08 10:02:56作者: o-Sakurajimamai-o

原代码 O(n2):  772ms

 

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10,M=1e4+10;
int n,m,res,f[N],p[N],a[N],s,k,level[N];
int e[N],ne[N],h[N],idx;
bool vis[N],mp[M][M];
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void topsort()
{
    queue<int>que;
    for(int i=1;i<=n;i++) if(!p[i]) que.push(i);
    while(!que.empty()){
        int now=que.front(); que.pop();
        for(int i=h[now];~i;i=ne[i]){
            int j=e[i];
            p[j]--;
            if(p[j]==0) level[j]=level[now]+1,que.push(j);
        }
    }
}

void spfa()
{
    queue<int>que;
    que.push(0),level[0]=0,vis[0]=true;
    while(!que.empty()){
        int now=que.front(); que.pop();
        vis[now]=false;
        for(int i=h[now];~i;i=ne[i]){
            int j=e[i];
            if(level[j]<level[now]+1){
                level[j]=level[now]+1;
                if(!vis[j]) vis[j]=true,que.push(j);
            }
        }
    }
}

int dfs(int u)
{
    if(level[u]) return level[u];
    for(int i=h[u];~i;i=ne[i]) level[u]=max(level[u],dfs(e[i])+1);
    return level[u];
}
signed main()
{
    std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n>>m;
    memset(h,-1,sizeof h);
    //memset(level,-0x3f,sizeof level);
    for(int i=0;i<m;i++){
        cin>>k;
        memset(vis,false,sizeof vis);
        for(int j=0;j<k;j++) cin>>a[j],vis[a[j]]=true;
        for(int j=a[0];j<=a[k-1];j++){
            if(vis[j]) continue;
            for(int e=0;e<k;e++)
                if(!mp[a[e]][j]) mp[a[e]][j]=true,add(a[e],j),p[j]++;//spfa是add(j,a[e])
        }
    }
    memset(vis,false,sizeof vis);
    //for(int i=1;i<=n;i++) add(0,i);
    //topsort();
    //spfa();
    //for(int i=1;i<=n;i++) res=max(res,level[i]);
    for(int i=1;i<=n;i++) if(!p[i]) res=max(res,dfs(i));
    //cout<<res<<endl;
    cout<<res+1<<endl;
    return 0;
}

考虑优化:

O(nm)

 

244ms / 13.34MB / 0.69KB
原本要连n2条边

 


但是,如果在中间添加一个虚点,就可以变成2n条边

 

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10,M=1e4+10;
int n,m,res,f[N],p[N],a[N],s,k,level[N];
int e[N],ne[N],h[N],idx;
bool vis[N],mp[M][M];
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void topsort()
{
    queue<int>que;
    for(int i=1;i<=n;i++) if(!p[i]) que.push(i);
    while(!que.empty()){
        int now=que.front(); que.pop();
        for(int i=h[now];~i;i=ne[i]){
            int j=e[i];
            p[j]--;
            if(p[j]==0) level[j]=level[now]+1,que.push(j);
        }
    }
}

void spfa()
{
    queue<int>que;
    que.push(0),level[0]=0,vis[0]=true;
    while(!que.empty()){
        int now=que.front(); que.pop();
        vis[now]=false;
        for(int i=h[now];~i;i=ne[i]){
            int j=e[i];
            if(level[j]<level[now]+1){
                level[j]=level[now]+1;
                if(!vis[j]) vis[j]=true,que.push(j);
            }
        }
    }
}

int dfs(int u)
{
    if(level[u]) return level[u];
    for(int i=h[u];~i;i=ne[i]) level[u]=max(level[u],dfs(e[i])+1);
    if(u>n) level[u]--;//这里注意,如果u层更新完了之后还是处于虚点,那就是没出去,要减1
    return level[u];
}
signed main()
{
    std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n>>m;
    memset(h,-1,sizeof h);
    //memset(level,-0x3f,sizeof level);
    for(int i=1;i<=m;i++){
        cin>>k;
        memset(vis,false,sizeof vis);
        for(int j=1;j<=k;j++) cin>>a[j],vis[a[j]]=true,add(n+i,a[j]);
        for(int j=a[1];j<=a[k];j++){
            if(vis[j]) continue;
            // for(int e=0;e<k;e++)
            //     if(!mp[a[e]][j]) mp[a[e]][j]=true,add(a[e],j),p[j]++;//spfa是add(j,a[e])
            add(j,n+i);//连入虚点
        }
    }
    memset(vis,false,sizeof vis);
    //for(int i=1;i<=n;i++) add(0,i);
    //topsort();
    //spfa();
    //for(int i=1;i<=n;i++) res=max(res,level[i]);
    for(int i=1;i<=n;i++) if(!level[i]) res=max(res,dfs(i));
    cout<<res<<endl;
    //cout<<res+1<<endl;
    return 0;
}