Codeforces Round #309 (Div. 1)D. Nudist Beach 二分+bfs

来源:互联网 发布:淘宝企业店铺开店要求 编辑:程序博客网 时间:2024/04/29 15:02

题目:http://codeforces.com/contest/553/problem/D

在一个无向图中,有若干坏点,选择一个不包含坏点的集合,使得集合中p值最小的点的p值最大。一个点的p值=集合中与该点相连的点的个数 / 与改点相连的总点数.


思路:考虑到p值是0到1的实数值,可以二分这个最小值。每次判断当前pi是否可以成立,做法是bfs。首先把所有点加进集合中,把不符合情况的点从集合中删除,删除的时候会影响到其他点,所以要维护一个欲删除点的队列,也就是bfs一遍,记住更新答案。

代码:

#include<iostream>#include<cstdio>#include<cstring>#include<queue>#include<vector>#include<set>using namespace std;typedef long long ll;const int N = 1e5+10;const double eps = 1e-8;vector<int> g[N];int n,m,k,vis[N];int kill[N];set<int> ss,ans_set;set<int>::iterator it;double ans = 0;int tmp[N];int ok(double p){    queue<int> q;    ss.clear();    memset(vis,0,sizeof(vis));    for(int i=1;i<=n;i++){        ss.insert(i);        tmp[i] = g[i].size();        if(kill[i]){            vis[i] = 1;            q.push(i);        }    }    while(!q.empty()){        int wt = q.front() ; q.pop();        ss.erase(wt);        for(int i=0;i<g[wt].size();i++){            int u = g[wt][i];            if(vis[u]) continue;            tmp[u]--;            double hc = 1.0*tmp[u]/g[u].size();            if(hc<p){                vis[u] = 1;                q.push(u);            }        }    }    int fl = 1;    for(it=ss.begin();it!=ss.end();it++)        if(1.0*tmp[*it]/g[*it].size() < p){ fl = 0 ; break;}    if(fl && ss.size()>0){        if(p>ans){            ans = p;            ans_set = ss;        }        return 1;    }    return 0;}int main(){    cin >> n >> m >> k;    ans_set.clear();    memset(kill,0,sizeof(kill));    for(int i=0;i<=n;i++) g[i].clear();    for(int i=1;i<=k;i++){        int x;        scanf("%d",&x);        kill[x] = 1;    }    for(int i=1;i<=m;i++){        int u,v;        scanf("%d%d",&u,&v);        g[u].push_back(v);        g[v].push_back(u);    }    int co = 0;    double high=1.0 , low = 0.0;    while(co<40){        co++;        double mid = (high + low)/2;        if( ok(mid) ) low = mid;        else high = mid;    }    if(ans_set.size()==0){        cout<<1<<endl;        for(int i=1;i<=n;i++) if(!kill[i])        {            cout<<i<<endl;            break;        }    }    else    {        cout<<ans_set.size()<<endl;        for(it=ans_set.begin();it!=ans_set.end();it++)            cout<<*it<<" ";        cout<<endl;    }    return 0;}
0 0