企鹅----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; }
一念起,天涯咫尺; 一念灭,咫尺天涯。