學了拆點之後,發現這題的構圖就很簡單了 , 不過昨天因為構圖時控制方向的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 initint 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;}