poj 3498(枚举人数+最大流) 满满都是泪
2014-09-10 22:17
387 查看
题意 : 在X,Y坐标系上有n个冰块,冰块上有一些企鹅,每个企鹅的跳跃距离都是d ,每个企鹅从一个冰块跳到另一个冰块时,冰块消耗一点承受度,冰块的承受压力是mi ,;
也就是每个冰块上的企鹅最多不能离开mi只 , 这些企鹅最终要汇聚在一块冰块上 ,求有哪些冰块可以当作聚集地 。
把n个冰块拆点为i,i+n , i只能企鹅进入,企鹅只能从i+n离开 ; i~i+n 流量为mi ,这样可以控制经过冰块的企鹅不会超过它的承受度 ; 源点s到每个冰块脸边,流量为冰块上企鹅的数量 ,然后冰块与冰块之间 ,如果i冰块与j冰块之间的距离小于d ,也就是这两个冰块上的企鹅可以互相跳过来 ; 那么连边 i冰块出口到j冰块入口,add(i+n,j,inf) ;
j冰块也可以去i冰块上面 add(j+n,i,inf) ; 然后枚举聚集地,若假设i冰块时最后的聚集地, 那么它的拆点之间流量改为inf ,因为所有企鹅都到它这里来,不会从该冰块出口离开 ;
不能限制流量为mi ; 最后聚集地到汇点连边 ,流量inf ; 跑一边最大流 ,最大流等于企鹅数量,即答案合理 !
注意存边开大一点 ,起码要10万; 还有两点间距离容易出错 ,该double的要double ! 坑了我一晚上 .
。
也就是每个冰块上的企鹅最多不能离开mi只 , 这些企鹅最终要汇聚在一块冰块上 ,求有哪些冰块可以当作聚集地 。
把n个冰块拆点为i,i+n , i只能企鹅进入,企鹅只能从i+n离开 ; i~i+n 流量为mi ,这样可以控制经过冰块的企鹅不会超过它的承受度 ; 源点s到每个冰块脸边,流量为冰块上企鹅的数量 ,然后冰块与冰块之间 ,如果i冰块与j冰块之间的距离小于d ,也就是这两个冰块上的企鹅可以互相跳过来 ; 那么连边 i冰块出口到j冰块入口,add(i+n,j,inf) ;
j冰块也可以去i冰块上面 add(j+n,i,inf) ; 然后枚举聚集地,若假设i冰块时最后的聚集地, 那么它的拆点之间流量改为inf ,因为所有企鹅都到它这里来,不会从该冰块出口离开 ;
不能限制流量为mi ; 最后聚集地到汇点连边 ,流量inf ; 跑一边最大流 ,最大流等于企鹅数量,即答案合理 !
注意存边开大一点 ,起码要10万; 还有两点间距离容易出错 ,该double的要double ! 坑了我一晚上 .
。
#include<cstdio> #include<cstring> #include<map> #include<vector> #include<cmath> #include<cstdlib> #include<stack> #include<queue> #include <iomanip> #include<iostream> #include<algorithm> using namespace std ; const int N=500 ; const int M=100000 ; const int inf=1<<30 ; struct node { int u ,v,c,next; }edge[M] ; struct node1 { int n,m ; double x,y; }e[M] ; int head ,dis ,gap ,cur ,pre ; int top , s,t,sum,n,nv; double d ; double Dis(int i,int j) { return sqrt(1.0*(e[i].x-e[j].x)*(e[i].x-e[j].x)+(e[i].y-e[j].y)*(e[i].y-e[j].y)); } void add(int u ,int v,int c) { edge[top].u=u; edge[top].v=v; edge[top].c=c; edge[top].next=head[u]; head[u]=top++; edge[top].u=v; edge[top].v=u; edge[top].c=0; edge[top].next=head[v]; head[v]=top++; } int sap() { memset(dis,0,sizeof(dis)); memset(gap,0,sizeof(gap)); int u,v,minflow=inf,flow=0; for(int i = 0 ; i <=nv ; i++) cur[i]=head[i] ; u=pre[s]=s; gap[s]=nv; while(dis[s] <= nv ) { loop : for(int &j=cur[u] ; j!=-1 ; j=edge[j].next) { v=edge[j].v ; if(edge[j].c > 0 && dis[u] == dis[v] +1 ) { minflow = min(minflow ,edge[j].c) ; pre[v]=u; u=v ; if(v==t) { for( u =pre[v] ; v!=s ;v=u,u=pre[u]) { edge[cur[u]].c -= minflow ; edge[cur[u]^1].c += minflow ; } flow += minflow ; minflow = inf ; } goto loop ; } } int mindis=nv ; for(int i = head[u] ; i!=-1 ; i=edge[i].next) { v=edge[i].v ; if(edge[i].c > 0 && dis[v] < mindis) { mindis = dis[v] ; cur[u]=i ; } } if(--gap[dis[u]]==0) break ; gap[ dis[u] = mindis +1 ]++ ; u=pre[u] ; } return flow ; } void make(int mid) { memset(head,-1,sizeof(head)) ; top = 0 ; s=0,t=2*n+1 ,nv=t+1 ; for(int i = 1 ; i <= n ; i++) { add(s,i,e[i].n) ; //源点连冰块 if(i==mid) //聚集地之间流量没有来限制 add(i,i+n,inf) ; else add(i,i+n,e[i].m) ;//限制企鹅数量 } for(int i = 1 ; i <= n ;i++ ) for(int j = i+1; j <= n ; j++) { if( Dis(i,j) <= d ) //i,j冰块可以互相到达 { add(i+n,j,inf) ,add(j+n,i,inf) ;//互相可以跳上去 } } } int main() { int tt ,f[200]; scanf("%d",&tt) ; while(tt--) { scanf("%d%lf",&n,&d) ; sum = 0; for(int i = 1 ; i <= n ; i++) { scanf("%lf%lf%d%d",&e[i].x,&e[i].y,&e[i].n,&e[i].m) ; sum += e[i].n ; } int k = 0 ; for(int i = 1 ; i <= n ; i++) { make(i) ; add(i+n,t,inf) ; //聚集地到汇点连边 if(sap()==sum) //i冰块可以作为聚集地 { f[k++]=i-1 ; } } if(k==0) printf("-1\n") ; else { printf("%d",f[0]) ; for(int i = 1 ; i < k ; i++) printf(" %d",f[i]) ; puts("") ; } } return 0 ; }
相关文章推荐
- POJ 3498 March of the Penguins(枚举+最大流)
- poj 3498(枚举加最大流dinic)
- POJ 3498 March of the Penguins(枚举+最大流)
- poj 3498 (最大流,枚举汇点)
- POJ 3498 —— March of the Penguins (枚举+最大流)
- POJ3498最大流,枚举终点,企鹅,基础最大流
- poj 3498(枚举汇点的最大流)
- POJ 3498 March of the Penguins(枚举+最大流)
- POJ - 3498 March of the Penguins 最大流(拆点 + 枚举汇点)
- POJ-2112 Floyd+二分枚举+最大流(or 匈牙利)
- poj 3498(最大流+拆点)
- poj 2112 二分枚举+最大流
- POJ-1043 What's In A Name? 反面构图+枚举边计算最大匹配
- 【POJ】1815 Friendship 枚举+最大流。。
- [省选前题目整理][POJ 2699]The Maximum Number of Strong Kings(暴力枚举+最大流)
- POJ 3189 枚举+最大流
- POJ 3498 March of the Penguins(网络最大流)
- poj 3498 March of the Penguins 点流量有限制的最大流
- POJ 1207 求最大数链长度 暴力枚举数学题
- POJ 2699 枚举+最大流