2020牛客寒假算法基础集训营6-图

本文解析了一道算法竞赛中的图论题目,重点讨论了如何处理非连通图的情况,通过拓扑排序和DFS策略找到最大链长和环的大小,从而确定最优解。文章提供了详细的代码实现和思路说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2020牛客寒假算法基础集训营6-图

好题
在这里插入图片描述
主要坑点在于有可能不是连通图。
那么对于一个连通图来说,肯定是一个环+n条链,那么最大值就是链的长度+环的大小。
所以可以先拓扑排序,把所有链都标记(剩下没有标记的点肯定在环上)。拓扑排序过程中dp存的值是dp【v】=max(dp【u】+1,dp【v】)表示该点最长延伸的长度(v有可能是环上的点这样ans=dp【v】+v所在环的长度-1)
之后dfs没有被标记的点,统计每个环的大小即可

#pragma GCC optimize(3,"Ofast","inline")    //G++
#include<bits/stdc++.h>
#define TEST freopen("C:\\Users\\hp\\Desktop\\ACM\\in.txt","r",stdin);
#define mem(a,x) memset(a,x,sizeof(a))
#define debug(x) cout << #x << ": " << x << endl;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define fcout cout<<setprecision(4)<<fixed
using namespace std;
typedef long long ll;
typedef pair<int,int> pi;
 
 
const int inf=0x3f3f3f3f;
const ll INF=0x7fffffffffffffff;
const int mod=1e9+7;
const int maxn = 1e6+5;
const double eps=1e-8;
 
template<typename T> void read(T &x){
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
    read(first);
    read(args...);
}
int sgn(double a){
    return a<-eps?-1:a<eps?0:1;
}
 
//inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int sub(int x,int y){return x-y<0?x-y+mod:x-y;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline int sq(int x){return 1ll*x*x%mod;}
int pow(int a,int b){return b == 0?1:( b&1?mul(a,sq(pow(a,b/2))):sq(pow(a,b/2)));}
 
vector<int>edge[maxn];
int n;
int in[maxn],to[maxn],vis[maxn],dp[maxn];
void add(int x,int y){
    edge[x].push_back(y);
}
void tupo(){
    queue<int>q;
    for(int i=1;i<=n;i++){
        dp[i]=1;
        if(!in[i]) q.push(i);
    }
    while(!q.empty()){
        int u=q.front();q.pop();
        vis[u]=1;
        for(auto v:edge[u]){
            dp[v]=max(dp[v],dp[u]+1);
            in[v]--;
            if(!in[v]) q.push(v);
        }
    }
}
int sum,maxx;
void dfs(int u){
 
    vis[u]=1;
    sum++;
    maxx=max(maxx,dp[u]);
    for(auto v:edge[u]){
        if(vis[v]) continue;
        dfs(v);
    }
}
int main()
{
    read(n);
    for(int i=1;i<=n;i++){
        read(to[i]);
        add(i,to[i]);
        in[to[i]]++;
    }
    tupo();
    int ans=0;
    for(int i=1;i<=n;i++){
        if(!vis[i]){
            sum=maxx=0;
            dfs(i);
            ans=max(ans,sum+maxx-1);
        }
    }
    cout<<ans<<"\n";
}

好题

当时比赛写的,,,现在看不懂了,好像是dfs+dfs…

#pragma GCC optimize(3,"Ofast","inline")    //G++
#include<bits/stdc++.h>
#define TEST freopen("C:\\Users\\hp\\Desktop\\ACM\\in.txt","r",stdin);
#define mem(a,x) memset(a,x,sizeof(a))
#define debug(x) cout << #x << ": " << x << endl;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define fcout cout<<setprecision(4)<<fixed
using namespace std;
typedef long long ll;
typedef pair<int,int> pi;


const int inf=0x3f3f3f3f;
const ll INF=0x7fffffffffffffff;
const int mod=1e9+7;
const int maxn = 1e6+5;
const double eps=1e-8;

template<typename T> void read(T &x){
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
    read(first);
    read(args...);
}
int sgn(double a){
    return a<-eps?-1:a<eps?0:1;
}

//inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int sub(int x,int y){return x-y<0?x-y+mod:x-y;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline int sq(int x){return 1ll*x*x%mod;}
int pow(int a,int b){return b == 0?1:( b&1?mul(a,sq(pow(a,b/2))):sq(pow(a,b/2)));}

vector<int>edge[maxn];
int n,flag,ans,__;
int to[maxn],vis[maxn],dp[maxn],re[maxn],root,siz[maxn],VIS[maxn];
int fin(int x){
    return re[x]==x?x:re[x]=fin(re[x]);
}
void uni(int x,int y){
    int xx=fin(x),yy=fin(y);
    if(xx!=yy)
        re[xx]=yy;
}
void add(int x,int y){
    edge[x].push_back(y);
}
void dfs1(int u,int op){

    vis[u]=op;
    for(auto v:edge[u]){
        if(vis[v]==op&&__){
            root=v;
            __=0;
        }
        if(!vis[v]){
            dfs1(v,op);
        }
    }
    if(flag||root==0){
        return ;
    }
    uni(u,root);
    siz[root]++;
    ans=max(ans,siz[root]);
    VIS[u]=1;
    if(u==root){
        flag=1;
    }
}
int dfs(int u){

   if(dp[u]) return dp[u];
//   vis[u]=1;C
   for(auto v:edge[u]) {

        if(VIS[v]){
            dp[u]=1+siz[fin(v)];
        }
        else
            dp[u]=1+dfs(v);
   }
   return dp[u];
}
int main()
{
    read(n);
    for(int i=1;i<=n;i++){
        re[i]=i;
        read(to[i]);
        add(i,to[i]);
    }
    int _=0;
    for(int i=1;i<=n;i++){
        root=flag=0;
        __=1;
        if(!vis[i]){
            dfs1(i,++_);
        }
    }
    mem(vis,0);
    for(int i=1;i<=n;i++){
        if(!VIS[i])
        {
            dfs(i);
            ans=max(ans,dp[i]);
        }
    }
    cout<<ans<<"\n";
}

还是拓扑排序好写@_@

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值