Description
战犯们企图逃离监狱,他们详细地计划了如何逃出监狱本身,逃出监狱之后他们希望在附近的一个村子里找到掩护。村子(下图中的B)和监狱(图中的A)中间有一个峡谷,这个峡谷也是有士兵守卫的。守卫峡谷的士兵们坐在岗哨上很少走动,每个士兵的观察范围是100米。士兵所处位置决定了战犯们能否安全通过峡谷,安全通过的条件就是在任何时刻战犯们距离最近的士兵大于100米。 给定峡谷的长、宽和每个士兵在峡谷中的坐标,假定士兵的位置一直保持不变,请你写一个程序计算战犯们能否不被士兵发现,顺利通过峡谷。如果不能,那么战犯们最少需要消灭几个士兵才能安全通过峡谷(无论士兵是否被另一个士兵看到,他都可以被消灭)。
Input
第一行有三个整数L、W和N,分别表示峡谷的长度、宽度和士兵的人数。接下来的N行,每行两个整数Xi和Yi,表示第i个士兵在峡谷的坐标(0 <= Xi <= L, 0 <= Yi <= W),坐标以米为单位,峡谷的西南角坐标为(0, 0),东北角坐标为(L, W),见上图。注意:通过峡谷可以从(0, ys)(0 <= ys <= W)到(L, ye)(0 <= ye <= W),其中ys, ye不一定是整数。
Output
只有一行,为一个整数,即安全通过峡谷需要消灭的士兵的人数,如果不需要消灭任何士兵,则输出0。
Sample Input
130 340 5
10 50
130 130
70 170
0 180
60 260
Sample Output
1
HINT
1 <= W <= 50,000 1 <= L <= 50,000 1 <= N <= 250
对于这道题,首先我们可以发现最后结果一定是一条穿过若干个类似下图的由士兵组成的集合,所以我们考虑设置超级源点和超
级汇点,对于每一个士兵,将其拆为两个点
和
,在两个点之间连一条权值为1的边,如果他的观察范围达到峡谷上端,则将
与超级源连一条权值为INF的边,如果他的观察范围达到峡谷下端,则将
与超级汇连连一条权值为INF的边,对于任意两个士兵
和
,如果他们的观察范围相交,则在
和
之间连一条权值为INF的边,那么最后的结果就是这张图的最小割,下面是程序:
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
const int N=200005,INF=0x7fffffff;
struct queue{
int l,r,a[N];
void clear(){
l=0,r=1;
}
bool empty(){
return l+1==r;
}
void push(int x){
a[r]=x;
r=(r+1)%N;
}
void pop(){
l=(l+1)%N;
}
int front(){
return a[(l+1)%N];
}
}q;
struct Point{
int x,y;
}a[N];
struct edge{
int v,w,next;
}e[N];
int head[N],k,d[N],s,t;
int abs(int n){
return n>0?n:-n;
}
int dis(Point a,Point b){
int x=a.x-b.x,y=a.y-b.y;
return x*x+y*y;
}
inline void add(int u,int v,int w){
e[k]=(edge){v,w,head[u]};
head[u]=k++;
e[k]=(edge){u,0,head[v]};
head[v]=k++;
}
bool BFS(){
q.clear();
memset(d,0,sizeof(d));
q.push(s);
d[s]=1;
int i,u;
while(!q.empty()){
u=q.front();
q.pop();
for(i=head[u];i!=-1;i=e[i].next){
if(!d[e[i].v]&&e[i].w){
d[e[i].v]=d[u]+1;
q.push(e[i].v);
}
}
}
return d[t];
}
int dfs(int u,int f){
if(u==t||f==0){
return f;
}
int i,t,use=0;
for(i=head[u];i!=-1;i=e[i].next){
if(d[e[i].v]==d[u]+1&&(t=dfs(e[i].v,min(f-use,e[i].w))>0)){
e[i].w-=t;
e[i^1].w+=t;
use+=t;
if(use==f){
return f;
}
}
}
return use;
}
int dinic(){
int ans=0;
while(BFS()){
ans+=dfs(s,INF);
}
return ans;
}
int main(){
int n,m,k,i,j;
scanf("%d%d%d",&n,&m,&k);
s=0,t=2*k+1;
memset(head,-1,sizeof(head));
for(i=1;i<=k;i++){
scanf("%d%d",&a[i].x,&a[i].y);
if(a[i].y<=100){
add(s,i,INF);
}
if(abs(a[i].y-m)<=100){
add(i+k,t,INF);
}
add(i,i+k,1);
}
for(i=1;i<=k;i++){
for(j=1;j<=k;j++){
if(i!=j&&dis(a[i],a[j])<=40000){
add(i+k,j,INF);
}
}
}
printf("%d\n",dinic());
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通