GYM - 101147 C.The Wall

题意:

  长和宽分别为M+N/2,N的矩形中。有很多敌人的点。有两种方法消灭敌人。

  1.N个桶,第i个桶可以消灭i-1<=x<i中的敌人。2.M个摆(半圆)每个摆可以消灭距离他前面不超过1以内的敌人。第i个摆的圆心在(N/2,i-1),半径都为N/2。

  问消灭所有敌人消耗的最少设备是多少。

题解:

  根据题意可以发现,每一个敌人都可以被桶消灭,但不一定被摆消灭。摆的盲区在第1个摆的内部和第M个摆两边的死角位置。

  所以出现在盲区的点必须被桶消灭。即那些桶是必选的。

  其余的点把消灭他的桶号和消灭他的摆号连边,跑一个最小顶点覆盖即可。

#include <bits/stdc++.h>
using namespace std;
int t;
int p;
double n, m;
int ans;
int vp[10005];
int vis[205];
int match[205];
struct ndoe {
    double x, y;
}w[10005];
double distance(double x1, double y1, double x2, double y2) {
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
vector<int> g[205];
bool dfs(int u) {
    for(int i = 0; i < g[u].size(); i++) {
        int v = g[u][i], w = match[v];
        if(vis[v]) continue;
        vis[v] = 1;
        if(w<0 || dfs(w)) {
            match[v] = u;
            return true;
        }
    }
    return false;
}
int hungarian() {
    int res = 0;
    memset(match, -1, sizeof(match));
    for(int u = 0; u < n; u++) {
        memset(vis, 0, sizeof(vis));
        if(dfs(u)) res++;
    }
    return res;
}
int main() {
    freopen("wall.in","r",stdin);
    scanf("%d", &t);
    while(t--) {
        ans = 0;
        memset(vp, 0, sizeof(vp));
        scanf("%lf%lf%d", &n, &m, &p);
        for(int i = 0; i < n+m; i++) g[i].clear();
        for(int i = 1; i <= p; i++) scanf("%lf%lf", &w[i].x, &w[i].y);
        memset(vis, 0, sizeof(vis));
        for(int i = 1; i <= p; i++) {
            if(distance(n/2, 0, w[i].x, w[i].y)<=n/2 || (w[i].y>m && distance(n/2, m-1, w[i].x, w[i].y)>1.0+n/2)) {
                vp[i] = 1;
                int v = (int)floor(w[i].x);
                if(vis[v]) continue;
                else {
                    vis[v] = 1; ans++;
                }
            }
        }
        for(int i = 1; i <= p; i++) {
            if(vp[i]) continue;
            int judge = (int)floor(w[i].x);
            if(vis[judge]) continue;
            int up = (int)floor(w[i].y);
            for(int v = up; v >= 0; v--) {
                if(distance(n/2, (double)v, w[i].x, w[i].y) > n/2) {
                    int u = (int)floor(w[i].x);
                    g[u].push_back(v+n); 
                    break;
                }
            }
        }
        ans += hungarian();
        printf("%d\n", ans);
    }
} 
View Code

 

posted @ 2018-04-21 13:33  Pneuis  阅读(298)  评论(0编辑  收藏  举报