CF1137C Museums Tour(tarjan+DP)

由于d很小,所以可以把每个点拆成d个点,然后对于边(x,y),连边时连接((x,i),(y,i+1))及((x,d),(y,1))。然后可以对这样连的边跑一遍tarjan缩点。然后直接暴力DP即可。不过当时比赛时不知道为什么一直写挂然后掉分了,后来发现用vector特别占用内存,要改成邻接表写。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
struct edge{int v,nxt;}e1[N*50],e2[N*50];
int n,m,d,tot,top,scc,cnt,hd1[N*50],hd2[N*50],val[N*50],bel[N*50],dfn[N*50],low[N*50],has[N*50],q[N*50],f[N*50];
char str[60];
void add1(int x,int y){e1[++cnt]=(edge){y,hd1[x]},hd1[x]=cnt;}
void add2(int x,int y){e2[++cnt]=(edge){y,hd2[x]},hd2[x]=cnt;}
void tarjan(int u)
{
    dfn[u]=low[u]=++tot;
    q[++top]=u;
    for(int i=hd1[u];i;i=e1[i].nxt)
    if(!dfn[e1[i].v])tarjan(e1[i].v),low[u]=min(low[u],low[e1[i].v]);
    else if(!bel[e1[i].v])low[u]=min(low[u],dfn[e1[i].v]);
    if(low[u]==dfn[u])
    {
        scc++;
        int now=0;
        while(now!=u)now=q[top--],bel[now]=scc;
    }
}
int dfs(int u)
{
    if(f[u]!=-1)return f[u];
    f[u]=0;
    for(int i=hd2[u];i;i=e2[i].nxt)f[u]=max(f[u],dfs(e2[i].v));
    return f[u]+=val[u];
}
int main()
{
    scanf("%d%d%d",&n,&m,&d);
    for(int i=1,x,y;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        for(int j=1;j<d;j++)add1(x+(j-1)*n,y+j*n);
        add1(x+(d-1)*n,y);
    }
    for(int i=1;i<=n*d;i++)if(!dfn[i])tarjan(i);
    cnt=0;
    for(int i=1;i<=n*d;i++)
    for(int j=hd1[i];j;j=e1[j].nxt)
    if(bel[i]!=bel[e1[j].v])add2(bel[i],bel[e1[j].v]);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",str+1);
        for(int j=1;j<=d;j++)
        if(str[j]=='1'&&has[bel[i+(j-1)*n]]!=i) 
        has[bel[i+(j-1)*n]]=i,val[bel[i+(j-1)*n]]++;
    }
    memset(f,-1,sizeof f);
    printf("%d",dfs(bel[1]));
}
View Code
原文地址:https://www.cnblogs.com/hfctf0210/p/10879861.html