Codeforces 1037E Trips【图论】【dfs】

这道题从看到到做出来有两周吧,一直头铁没有看题解,有一天走路的时候突然就想懂了。有点爽!

该题的子问题是给一个图,让找其中一个子图使得子图中的每个节点度都大于等于k。怎么解决?

把这个图里面小于k个度的结点都删掉不就行了,注意这里要用dfs,因为删除u结点后,可能导致v结点的度也不到k了(为了避免重复删除建了一个erase数组)。想到这个的话就差不多做出来了

肯定能想到反向回答问题,因为删边好解决。把那两个点的度都减一,如果小于k就删除掉。【这里删边我用了map,感觉很神器,因为直接按下标就能删了】

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<algorithm>
#include<vector>
#define INF 2e9
using namespace std;

map<int,bool> mp[200005];
vector<int> ans;
int u[200005],v[200005],degree[200005],k;
int erase[200005];

int delet(int u){//返回删除u这个人,所产生的总效应(导致一共要删多少人) 
    int cnt=1;//已经删了u这个人 
    erase[u]=1;
    map<int,bool>::iterator it=mp[u].begin();
    for(;it!=mp[u].end();it++){
        int v=it->first;
        if( !erase[v] ){//只有当v没被删除的时候才需要考虑 
            degree[v]--;
            if( degree[v]<k ) cnt+=delet(v); 
        }
    }
    return cnt;
}

int main(){
    ios::sync_with_stdio(false);
    int n,m; cin>>n>>m>>k;
    for(int i=1;i<=m;i++){
        cin>>u[i]>>v[i];
        degree[ u[i] ]++; degree[ v[i] ]++;
        mp[ u[i] ][ v[i] ]=1;
        mp[ v[i] ][ u[i] ]=1;
    }
    
    int count=n;
//    cout<<count<<endl;
    for(int i=1;i<=n;i++){//
        if( !erase[i] && degree[i]<k ) {
            count-=delet(i);
        //    cout<<i<<" "<<count<<endl;
        }    
    }
//    cout<<"!!!"<<endl;
    for(int i=m;i>=1;i--){
    //    cout<<count<<endl;
        ans.push_back( count );
        if( erase[ u[i] ] || erase[ v[i] ] ) continue;
    //    cout<<u[i]<<" "<<v[i]<<" "<<degree[ u[i] ]<<" "<<degree[ v[i] ]<<endl;
        degree[ u[i] ]--; degree[ v[i] ]--; 
        mp[ u[i] ].erase( v[i] ); mp[ v[i] ].erase( u[i] );
        if( degree[ u[i] ]<k ) count-=delet( u[i] );
        if( !erase[ v[i] ] && degree[ v[i] ]<k ) count-=delet( v[i] );//删除u[i]可能导致把v[i]删除掉 
        
    }
    
    reverse(ans.begin(),ans.end());
    for(int i=0;i<ans.size();i++) cout<<ans[i]<<endl;
    
    return 0;    
}

猜你喜欢

转载自www.cnblogs.com/ZhenghangHu/p/9689311.html