1. 程式人生 > >Codeforces Round #545 (Div. 2) E 強連通塊 + dag上求最大路徑 + 將狀態看成點建圖

Codeforces Round #545 (Div. 2) E 強連通塊 + dag上求最大路徑 + 將狀態看成點建圖

[1] spa its 聯通塊 def com += main efi

https://codeforces.com/contest/1138/problem/E

題意

有n個城市(1e5),有m條單向邊(1e5),每一周有d天(50),對於每個城市假如在某一天為1表示這天城市博物館開放,反之閉館,問你最多能去多少個博物館

題解

  • 第一個分出來的強連通塊是dag的起點
  • 假設博物館每天都開放,那麽求出圖的強連通塊後,dag上dp就行
  • 現在加上有d天的話,只需要加多一維構成狀態,然後將狀態一維化看成點,再建圖
  • 計數的時候註意每個強聯通塊裏面每個城市只能選一次

代碼(鏈式前向星scc)

#include<bits/stdc++.h>
#define N 100005
#define D 55
#define MAXN N*D
using namespace std;
int hd[MAXN],nt[MAXN],to[MAXN],cnt;
int hd2[MAXN],nt2[MAXN],to2[MAXN],cnt2;
int dfn[MAXN],low[MAXN],vis[MAXN],stk[MAXN],top,Time,scc,blk[MAXN];
int dp[MAXN],sz[MAXN];
int n,m,d,u,v;
char s[N][D];

int id(int a,int b){
    return (a-1)*d+b%d+1;
}
void add(int u,int v){
    nt[++cnt]=hd[u];to[cnt]=v;hd[u]=cnt;
}
void add2(int u,int v){
    nt2[++cnt2]=hd2[u];to2[cnt2]=v;hd2[u]=cnt2;
}
void tarjan(int u){
    dfn[u]=low[u]=++Time;
    stk[++top]=u;vis[u]=1;
    for(int i=hd[u];i;i=nt[i]){
        int v=to[i];
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }else if(vis[v]){
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(dfn[u]==low[u]){
        ++scc;
        for(;;){
            int x=stk[top];top--;
            vis[x]=0;blk[x]=scc;
            if(x==u)break;
        }
    }
}
void dfs(int u){
    if(dp[u])return;
    for(int i=hd2[u];i;i=nt2[i]){
        int v=to2[i];
        dfs(v);
        dp[u]=max(dp[u],dp[v]);
    }
    dp[u]+=sz[u];
    return;
}
int main(){
    scanf("%d%d%d",&n,&m,&d);
    for(int i=0;i<m;i++){
        scanf("%d%d",&u,&v);
        for(int j=0;j<d;j++)
            add(id(u,j),id(v,(j+1)%d));
    }
    for(int i=1;i<=n;i++)scanf("%s",s[i]);
    for(int i=1;i<=n*d;i++){
        if(!dfn[i])tarjan(i);
    }
    for(int i=1;i<=n;i++){
        for(int j=0;j<d;j++){
            int x=id(i,j);
            if(s[i][j]=='1'&&vis[blk[x]]!=i){
                sz[blk[x]]++;
                vis[blk[x]]=i;
            }
            for(int k=hd[x];k;k=nt[k]){
                int v=to[k];
                if(blk[v]!=blk[x])add2(blk[x],blk[v]);
            }
        }
    }
    dfs(blk[1]);
    printf("%d",dp[blk[1]]);
}

Codeforces Round #545 (Div. 2) E 強連通塊 + dag上求最大路徑 + 將狀態看成點建圖