多校第十场HRBEU&&HDU 3931Cross the Fire(最小权点割+拆点+BT构图思想)

来源:互联网 发布:查看win7开放的端口 编辑:程序博客网 时间:2024/06/08 19:15
题意:一个hero要超越雷区,hero有一定的血,触雷要掉一定血,雷是已知半径和杀伤力的,求hero能否活着穿过雷区,且耗费最少的血;

题解:我们将所有的圆映射成无向图上的点,并且把任意两个相交的圆(包括相切和包含)之间连上一条无向边;将上边界当成逻辑源点,下边界当成逻辑汇点,所有与之相交的圆都分别向它们连上一条有向边。
模型抽象为若存在一条从源点到汇点的独立轨,则人必须触一次雷,而人想通过街道,意味着要破坏这些独立轨,使得源点和汇点之间失去连通性。
这个显然是一个无向图的最小权点割问题了。
将除了源汇点之外的内点全部拆点,原来的点权转化为边容量,其它边的边容量为正无穷,接着从源点向汇点压流。
最后比较一下最大流值和人的初始体力值即是最后的答案。

网络流的重点是构图,看了图解之后,直接敲完就AC了。

 

#include <cstdio>#include <cstring>const int maxN=255;const int maxn=550;const int inf=1<<25;const int s=0;int L , W , N , P;struct edge{       int v,next,w;}edge[maxn*maxn];int head[maxn],cnt;//for sap void addedge(int u, int v, int w){     edge[cnt].v=v;     edge[cnt].w=w;     edge[cnt].next=head[u];     head[u]=cnt++;     edge[cnt].v=u;     edge[cnt].w=0;     edge[cnt].next=head[v];     head[v]=cnt++;}int sap(int t){    int pre[maxn],cur[maxn],dis[maxn],gap[maxn];    int flow=0 , aug=inf ,u;    bool flag;    for (int i=0 ; i<=t ; ++i)    {        cur[i]=head[i];        gap[i]=dis[i]=0;    }    gap[s]=t+1;    u=pre[s]=s;    while (dis[s]<=t)    {          flag=0 ;           for (int &j=cur[u] ; ~j ; j=edge[j].next)          {              int v=edge[j].v;              if (edge[j].w>0 && dis[u]==dis[v]+1)              {                   flag=1;                   if(edge[j].w<aug)aug=edge[j].w;                   pre[v]=u;                   u=v;                   if (u==t)                   {                       flow+=aug;                       while (u!=s)                       {                             u=pre[u];                             edge[cur[u]].w-=aug;                             edge[cur[u]^1].w+=aug;                       }                       aug=inf;                       }                     break;                      }          }          if (flag)continue ;          int mindis=t+1;          for (int j=head[u]; ~j ; j=edge[j].next)          {              int v=edge[j].v;              if (edge[j].w>0 && dis[v]<mindis)              {                 mindis=dis[v];                 cur[u]=j;              }                    }          if(--gap[dis[u]]==0)break;          gap[dis[u]=mindis+1]++;          u=pre[u];    }    return flow;}int x[maxN],y[maxN],r[maxN],p[maxN];//for build graphbool intersect (int a,int b){     int dis=(x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]);     if(dis<=((r[a]+r[b])*(r[a]+r[b])))return true ;     else return false ;}void build_graph(){     int n=2*N;     for (int i=1 ; i<=N ; ++i)     {         addedge (i,i+N,p[i]);         if(y[i]<=r[i])addedge(0,i,inf);         if(y[i]+r[i]>=W)addedge(i+N,n+1,inf);         for (int j=i+1 ; j<=N ; ++j)//         if(intersect(i,j))addedge(i+N,j,inf),addedge(j+N,i,inf);     }}void init (){     memset (head , -1 , sizeof(head));     cnt=0;}int main (){    while (~scanf("%d%d%d%d",&L,&W,&N,&P))    {          init();          for (int i=1 ; i<=N ; ++i)           scanf("%d %d %d %d",x+i,y+i,r+i,p+i);          build_graph();          int ans=P-sap(2*N+1);          if(ans<0)printf("Our hero has been killed\n");          else printf("%d\n",ans);    }    return 0;}


 

原创粉丝点击