0
点赞
收藏
分享

微信扫一扫

CF:1674 G. Remove Directed Edges

花明 2022-05-03 阅读 44
算法

题目链接

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

(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 条评论