您的位置:首页 > 其它

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 ! 坑了我一晚上 .





#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 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: