JOJ 2724 hua rong dao (最小割 拆点)[无代码]

学了拆点之后,发现这题的构图就很简单了 , 不过昨天因为构图时控制方向的k的范围出了点小问题 , 本应k<4 ,却写成了k<3 , 导致卡了一天 , 今天重写一遍的时候发现了这个问题 , 改过来之后就AC了,时间跑了第一^ ^ 。

题意:曹操在一个area上,孙刘联军为了防止曹操逃跑就必须设法堵住他的所有逃跑去路,即不能达到area的边缘。

构图的方法就是:

1.设置一个额外源点与所有边界点相连 , 一个额外汇点与所有0相连 ,由于对于所有-1我们可以看成是需要0的时间去毁掉它 , 所以可以直接将其忽略。

2.每个非零点与其相邻4个非零顶点相连建立无向边 , 向零点连有向边 。

3.将点拆成边,零边赋为infinty, 非零点赋值为该点值 ,之后直接求最小割即可。

 

 

#include <cstdio>
#include <cstring>

const int maxn=1850;
const int inf=1<<29;
const int s=0;//source 

struct edge{
       int v,next,w;
}edge[maxn*8];
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;
                       //printf("%d %d \n", 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 r,c,map[35][35];//for init
int dir[4][2]={0,1 , 1,0 , -1,0 , 0,-1};

void build_graph()
{
    int i,j;
    int num=r*c;
    for (int i=0 ; i<r ; ++i)
    {
        for (int j=0 ; j<c ; ++j)
        {
            if(map[i][j]==-1)continue;
            if(i==0 || j==0 || i==r-1 || j==c-1)//map if on the edge of the area
            {
                if(~map[i][j])addedge(0 , i*c+j+1 , inf);
                                //addedge (i*r+j+1 , i*r+j+1+r*c , map[i][j]);
            }
            else if(!map[i][j])//map is 0 
            {
                addedge(i*c+j+1+r*c , r*c*2+1 , inf);
                addedge(i*c+j+1 , r*c+i*c+j+1 , inf);
            }
            if(map[i][j])
            {
                for (int k=0 ; k<4 ; ++k)
                {
                    int x=i+dir[k][0],y=j+dir[k][1];
                    if(x<0 || y<0 || x>=r || y>=c)continue ;
                    if(!map[x][y])addedge(i*c+j+1+r*c , x*c+y+1 , inf);
                    else 
                    addedge(x*c+y+1+r*c , i*c+j+1 , inf),
                            addedge(i*c+j+1+r*c , x*c+y+1 , inf);
                }
                addedge(i*c+j+1,i*c+j+1+r*c,map[i][j]);
            }
        }
    }
}

void init ()
{
     memset (head , -1 , sizeof(head));
     cnt=0;
}

int main ()
{
    int cas;
    scanf("%d",&cas);
    while (cas--)
    {
        init();
        scanf("%d%d",&r,&c);
        for (int i=0 ; i<r ; ++i)
         for (int j=0 ; j<c ; ++j)
         {
              scanf("%d",(*(map+i)+j));
         }
         build_graph();
         printf("%d\n",sap(r*c*2+1));
    }
    return 0;
}


 

 

 

你可能感兴趣的:(DAO,c,struct,SAP,Graph,Build)