CF:1674 G. Remove Directed Edges

该博客讨论了一个有向无环图(DAG)的问题,目标是通过删除边使得每个节点的出度和入度减少,同时确保存在一个点集S,其中任意两点间存在路径。采用动态规划的方法求解,状态表示为以某个节点为起点的最长链长度。通过遍历并更新每个节点的状态,最终找到所有节点中最大链长度的答案。
摘要由CSDN通过智能技术生成

题目链接

题意:给出有向无环图,删去若干条边,使得满足以下两个条件:

(1)对于每一个结点,其出边比原来少,除非初始出边就为0;

(2)对于每一个结点,其入边比原来少,除非初始入边就为0;

操作后,选择一个点集S,S中的任意两个元素u,v都满足:u能到v或者v能到u。

请得到最大的|S|

题解:由于是个有向无环图。所以S中的点一定是从u能到v,而v到不了u。

那么S集合一定是一条链上的所有点;

发现了这个问题后就好写了,可以发现用dp做。

状态表示:f[u]表示操作后以u为起点的最长链。

状态转移:f[u]=f[u]+max(f[v1],f[v2],f[v3]...);

状态转移的条件:u结点的出度>1,v结点的入度>1

为什么是这样转移,为什么是这样的条件,自己画个图想把,很容易想明白的。

最后答案就是所有点的f[u]中的最大值

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int n,m,idx;
int h[maxn];
struct Edge{
    int v,nxt;
}edge[maxn<<1];
int f[maxn],din[maxn],dout[maxn];
void add(int u,int v){
    edge[idx].v=v;
    edge[idx].nxt=h[u];
    h[u]=idx++;
}
void dfs(int u){
    if(f[u]) return ;
    f[u]=1;
    for(int i=h[u];~i;i=edge[i].nxt){
        int v=edge[i].v;
        dfs(v);
    }
    int d=0;
    for(int i=h[u];~i;i=edge[i].nxt){
        int v=edge[i].v;
        if(dout[u]>1&&din[v]>1)
            d=max(d,f[v]);
    }
    f[u]+=d;
}
void solve(){
    memset(h,-1,sizeof(h));
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int u,v;
        cin>>u>>v;
        add(u,v);
        din[v]++;dout[u]++;
    }
    for(int i=1;i<=n;i++){
        if(!din[i]){
            dfs(i);
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        ans=max(ans,f[i]);
    }
    cout<<ans<<'\n';
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;t=1;
    while(t--) solve();
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值