题解:P8073 [COCI2009-2010#7] BAKICE
水题。
思路
,考虑直接模拟。
我们首先预处理出人和座位之间的距离,数组记为 。
然后把 按距离排序。
对于一条边,连接人 和座椅 ,我们这么处理:
- 人 已经坐上座位。显然一定有一个座位,使得在这个人的位置出发,距离更短。所以这个座位不是答案。
- 人 还没有坐上座位,同时座位 还没有人坐。那么人 坐在座位 上一定最优。证明:如果再往后走,还有一个人 可以坐的座位,人 到这个座位的距离一定更长。
- 人 还没有坐上座位,但是这个座位 被另一个人 坐了,并且这个人 到座位 的距离比另一个人 到座位 的距离大。这样这个人 就无法坐在这个座位上,只能再往后找。
- 人 还没有坐上座位,但是这个座位 被另一个人 做了,但是这个人 和另一个人 到这个座位 的距离一致。自然会发生爆炸。
于是可以写出代码:
for(int i=1;i<=cnt;i++){
int u=e[i].u,v=e[i].v;
if(vis[u]){
continue;
}
if(!zhan[v]){
vis[u]=v;
zhan[v]=u;
sum[v]++;
}
else{
double dis=e[i].dis;
double dis1=sqrt((sx[v]-px[zhan[v]])*(sx[v]-px[zhan[v]])+(sy[v]-py[zhan[v]])*(sy[v]-py[zhan[v]]));
if(dis==dis1){
zhan[v]=u;
vis[u]=v;
sum[v]++;
ans++;
}
}
}
但是这个代码是错误的。原因是:如果 个人同时抢一个座位,这个代码会统计 次。很显然:除了第一个人,后面所有人枚举到这个位置,都会有一个人在这上面,触发 ans++ 的条件。
举个例子:
3 3
.X.
XLX
.X.
很显然四个人都会抢一个位置,发生一次爆炸,但是这个代码会输出 。
因为我们在枚举到第二个人时,判断第一个人占掉了,距离一致,答案增加;在枚举到第三个人时,判断第二个人占掉了,距离一致,答案增加;在枚举到第四个人时,判断第三个人占掉了,距离一致,答案也增加。
如何避免这个问题?我们需要一个 sum 数组,统计抢这个位置的人数。如果多于 ,则会发生爆炸,答案增加。
代码
#include<bits/stdc++.h>
using namespace std;
struct node{
int u,v;
double dis;
}e[10005];
char ch[105][105];
int n,m,cnt1,cnt2,cnt;
int px[10005],py[10005],sx[10005],sy[10005];
int vis[10005];
bool cmp(node _,node __){
return _.dis<__.dis;
}
int zhan[10005],sum[10005];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>ch[i][j];
if(ch[i][j]=='X'){
px[++cnt1]=i;
py[cnt1]=j;
}
if(ch[i][j]=='L'){
sx[++cnt2]=i;
sy[cnt2]=j;
}
}
}
for(int i=1;i<=cnt1;i++){
for(int j=1;j<=cnt2;j++){
e[++cnt].u=i;
e[cnt].v=j;
e[cnt].dis=sqrt((sx[j]-px[i])*(sx[j]-px[i])+(sy[j]-py[i])*(sy[j]-py[i]));
}
}
sort(e+1,e+cnt+1,cmp);
for(int i=1;i<=cnt;i++){
int u=e[i].u,v=e[i].v;
if(vis[u]){
continue;
}
if(!zhan[v]){
vis[u]=v;
zhan[v]=u;
sum[v]++;
}
else{
double dis=e[i].dis;
double dis1=sqrt((sx[v]-px[zhan[v]])*(sx[v]-px[zhan[v]])+(sy[v]-py[zhan[v]])*(sy[v]-py[zhan[v]]));
if(dis==dis1){
zhan[v]=u;
vis[u]=v;
sum[v]++;
}
}
}
int ans=0;
for(int i=1;i<=cnt2;i++){
if(sum[i]>1)ans++;
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号