您的位置:首页 > 其它

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

2015-06-28 19:39 330 查看
题目:http://codeforces.com/contest/553/problem/D

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

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

代码:

[code]#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
;
int n,m,k,vis
;
int kill
;
set<int> ss,ans_set;
set<int>::iterator it;
double ans = 0;
int tmp
;

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: