企鹅----sap+裂点
企鹅
题目描述
在靠近南极的某处,一些企鹅站在许多漂浮的冰块上。由于企鹅是群居动物,所以它们想要聚集到一起,在同一个冰块上。企鹅们不想把自己的身体弄湿,所以它们在冰块之间跳跃,但是它们的跳跃距离,有一个上限。
随着气温的升高,冰块开始融化,并出现了裂痕。而企鹅跳跃的压力,使得冰块的破裂加速。幸运的是,企鹅对冰块十分有研究,它们能知道每块冰块最多能承受多少次跳跃。对冰块的损害只在跳起的时候产生,而落地时并不对其产生伤害。
现在让你来帮助企鹅选择一个冰面使得它们可以聚集到一起。
输入
第一行整数N,和浮点数D,表示冰块的数目和企鹅的最大跳跃距离。
(1≤N ≤100) (0 ≤D ≤100 000),
接下来N行,xi, yi, ni and mi,分别表示冰块的X和Y坐标,该冰块上的企鹅数目,以及还能承受起跳的次数。
输出
输出所有可能的相聚冰块的编号,以0开始。如果不能相遇,输出-1。
样例输入
5 3.5
1 1 1 1
2 3 0 1
3 5 1 1
5 1 1 1
5 4 0 1
样例输出
1 2 4
题解:
这应该是一道网络流的经典应用。。
每个点上有企鹅,但也有起跳限制,我们可以把这些看作流量。。
将i拆成i和n+i,n+i是可起跳点,i是可跳到的点。。
设一个超级源点src,则一开始
add(src,i,c)//c为企鹅数
add(i,i+n,d)//d为起跳限制
如果两块冰的距离小于限制,也可以连边。
#include<stdio.h>
#include<iostream>
using namespace std;
const int N=205;
double d;
int n,m,i,ans,sum,x,y,j,p,src,tar,dis[N],gap[N],a[N],b[N],c[N];
int tot,head[N],Next[60005],to[60006],v[60005],len[60005];
void add(int x,int y,int z)
{
to[tot]=y;
v[tot]=z;
len[tot]=z;
Next[tot]=head[x];
head[x]=tot++;
}
inline int isap(int x,int s)
{
if(x==tar) return s;
int flow=0,Min=n-1,i;
for(i=head[x];i!=-1;i=Next[i])
{
int y=to[i];
if(v[i]>0)
{
if(dis[x]==dis[y]+1)
{
int tmp=isap(y,min(s-flow,v[i]));
flow+=tmp;
v[i]-=tmp;
v[i^1]+=tmp;
}
Min=min(Min,dis[y]);
}
if(flow==s) return flow;
if(dis[src]==n) return flow;
}
if(flow==0)
{
gap[dis[x]]--;
if(gap[dis[x]]==0) dis[src]=n;
dis[x]=Min+1;
gap[dis[x]]++;
}
return flow;
}
int main()
{
scanf("%d%lf",&m,&d);
n=m*2+1;src=n;
for(i=1;i<=n;i++) head[i]=-1;
for(i=1;i<=m;i++)
{
scanf("%d%d%d%d",&a[i],&b[i],&x,&y);
sum+=x;
add(n,i,x);add(i,n,0);
add(i,i+m,y);add(i+m,i,0);
for(j=1;j<i;j++)
if(1.0*((a[i]-a[j])*(a[i]-a[j])+(b[i]-b[j])*(b[i]-b[j]))<=d*d)
{
add(m+i,j,1e9);add(j,m+i,0);
add(m+j,i,1e9);add(i,m+j,0);
}
}
for(i=1;i<=m;i++)
{
gap[0]=n;
for(j=1;j<=n;j++) gap[j]=dis[j]=0;
for(j=0;j<tot;j++) v[j]=len[j];
ans=0;tar=i;
while(dis[n]<n)
ans+=isap(n,1e9);
if(ans==sum)
{
if(p) printf(" ");
p=1;
printf("%d",i-1);
}
}
if(p==0) printf("-1");
return 0;
}
一念起,天涯咫尺; 一念灭,咫尺天涯。

浙公网安备 33010602011771号