CF553D Nudist Beach

题目地址

这里

Solution

一道比较简单的二分

先分析一下题目性质:任意城市被敌军占领,其周围城市的安全度都会降低\(\implies\)
我们在选取城市时,应遵循这样一个原则:所有能够被己方控制的城市都应当让己方控制。

这里的“能够”当然只在二分答案的限制下才有意义。

那么,解决方法就很简单了。
利用队列,先将必须被敌军占领(有堡垒)的城市入队,将队列中的城市一个个拿出来更新其周围城市的安全度,如果更新后安全度小于\(mid\)就将这个城市入队。

如果最后还有城市未被敌军占领,\(l = mid\)否则,\(r = mid\),最终\(l\)为最大安全度。

另外,这道题对精度的要求比较高,我设置的精度是\(10^{-9}\)\(10^{-8}\)以上大概就过不了了。

Code

#include <bits/stdc++.h>

using namespace std;

const int MAXN = 1e5 + 10;
const double eps = 1e-9;

int n,m,k,siz[MAXN];
int num[MAXN],d[MAXN];//d:某城市周围被敌军占领的城市数量。
bool vis[MAXN];
vector<int> e[MAXN];
queue<int> q;

bool judge(double mid) {
    memset(vis,false,sizeof(vis));
    memset(d,false,sizeof(d));
    for (int i = 1; i <= k; i++) {
        q.push(num[i]);vis[num[i]] = true;
        for (int j = 0; j < siz[num[i]]; j++) {
            d[e[num[i]][j]]++;
        }
    }
    while (!q.empty()) {
        int u = q.front();q.pop();
        int len = e[u].size();
        for (int i = 0; i < len; i++) {
            int v = e[u][i];
            if (vis[v]) continue;
            double nu = ((siz[v] - d[v]) * 1.0 / siz[v]);
            if (nu < mid) {
                vis[v] = true;
                for (int j = 0; j < siz[v]; j++) {
                    d[e[v][j]]++;
                }
                q.push(v);
            }
        }
    }
    for (int i = 1; i <= n; i++) if (!vis[i]) return true;
    return false;
}

int main() {
    scanf("%d%d%d",&n,&m,&k);
    for (int i = 1; i <= k; i++) {
        scanf("%d",&num[i]);
    }
    for (int i = 1; i <= m; i++) {
        int u,v;
        scanf("%d%d",&u,&v);
        e[u].push_back(v);
        e[v].push_back(u);
    }
    for (int i = 1; i <= n; i++) siz[i] = e[i].size();
    double l = 0,r = 1.0;
    while (r - l > eps) {
        double mid = (l + r) / 2;
        if (judge(mid)) l = mid;
        else r = mid;
    }
    memset(vis,false,sizeof(vis));
    judge(l);
    int cnt = 0;
    for (int i = 1; i <= n; i++) {
        if (!vis[i]) {
            cnt++;
        }
    }
    cout << cnt << endl;
    for (int i = 1; i <= n; i++) {
        if (!vis[i]) printf("%d ",i);
    }
    return 0;
}
posted @ 2021-02-05 16:55  kjd123456  阅读(165)  评论(0编辑  收藏  举报