【hdu 4859】海岸线(图论--网络流最小割)
题意:有一个区域,有'.'的陆地,'D'的深海域,'E'的浅海域。其中浅海域可以填充为陆地。这里的陆地区域不联通,并且整个地图都处在海洋之中。问填充一定浅海域之后所有岛屿的最长的海岸线之和。
解法:最小割。从“分隔”陆地和海域可以想到“割”的概念,然后我们先不考虑浅海域,要深海域和陆地的对数尽量大,也就是相同的地理构造对数尽量小。
于是我们建立一个二分图,深海域和陆地都分列两侧,对于相邻的一个在左,一个在右,也就是“行+列”是奇数的放左,偶数的在右。而对于相邻的深海域和陆地,它们在图中理应分列两侧,才有“相连”的意义。(唉,我算是“梗着脖子”地在解释......~(-仝-)~)于是可以深海域的奇数的在左,而陆地的偶数的在左。
接着建立一个源点和汇点,左侧的点与源点相连,右侧的点与汇点相连。由于无约束,边容量为INF。而4个方向相邻的都“相连”,便建边,容量为1,表示割这条边的代价就是1。又因为这整个地图都处在海洋之中,也就是这个地图外围是一圈深海域,这是隐含条件,所以还需要另外建这些点和对应的边。
最后,用最大流算法求出最小割,表示相同的地理构造的最少的对数,而最长的海岸线就是最多的不同的构造,也就是总对数-最少的相同的地理构造的对数。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<queue> 6 using namespace std; 7 8 const int N=50,NN=3000,MM=30000,INF=20000; 9 int n,m,len=1; 10 int last[NN],d[NN]; 11 int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0}; 12 char s[N][N]; 13 struct node{int x,y,fl,next;}a[MM]; 14 queue<int> q; 15 16 int mmin(int x,int y) {return x<y?x:y;} 17 void ins(int x,int y,int fl) 18 { 19 a[++len].x=x,a[len].y=y,a[len].fl=fl; 20 a[len].next=last[x],last[x]=len; 21 a[++len].x=y,a[len].y=x,a[len].fl=0; 22 a[len].next=last[y],last[y]=len; 23 } 24 bool bfs(int st,int ed) 25 { 26 while (!q.empty()) q.pop(); 27 memset(d,0,sizeof(d)); 28 q.push(st); d[st]=1; 29 while (!q.empty()) 30 { 31 int x=q.front(); q.pop(); 32 for (int i=last[x];i;i=a[i].next) 33 { 34 int y=a[i].y; 35 if (!a[i].fl||d[y]) continue; 36 d[y]=d[x]+1; q.push(y); 37 } 38 } 39 return d[ed]; 40 } 41 int dfs(int x,int flow,int ed) 42 { 43 if (x==ed) return flow; 44 int sum=0; 45 for (int i=last[x];i;i=a[i].next) 46 { 47 int y=a[i].y; 48 if (d[y]!=d[x]+1||!a[i].fl) continue; 49 int t=dfs(y,mmin(flow-sum,a[i].fl),ed); 50 sum+=t; 51 a[i].fl-=t,a[i^1].fl+=t; 52 if (sum==flow) break; 53 } 54 if (!sum) d[x]=0; 55 return sum; 56 } 57 int Max_flow(int st,int ed) 58 { 59 int sum=0; 60 while (bfs(st,ed)) sum+=dfs(st,INF,ed); 61 return sum; 62 } 63 int ID(int x,int y) {return (x-1)*m+y;} 64 int main() 65 { 66 int T; 67 scanf("%d",&T); 68 for (int kase=1;kase<=T;kase++) 69 { 70 scanf("%d%d",&n,&m); 71 for (int j=1;j<=m+2;j++) s[1][j]='D'; 72 for (int i=2;i<=n+1;i++) 73 { 74 scanf("%s",s[i]+2); 75 s[i][1]=s[i][m+2]='D'; 76 } 77 for (int j=1;j<=m+2;j++) s[n+2][j]='D'; 78 n+=2,m+=2; 79 80 int st=n*m+1,ed=n*m+2; 81 memset(last,0,sizeof(last)); 82 len=1; 83 for (int i=1;i<=n;i++) 84 { 85 for (int j=1;j<=m;j++) 86 { 87 if (i==1||i==n||j==1||j==m) s[i][j]='D'; 88 int t=ID(i,j); 89 if (s[i][j]=='.') 90 { 91 if ((i+j)%2) ins(st,t,INF); 92 else ins(t,ed,INF); 93 } 94 if (s[i][j]=='D') 95 { 96 if ((i+j)%2) ins(t,ed,INF); 97 else ins(st,t,INF); 98 } 99 for (int k=0;k<4;k++) 100 { 101 int x=i+dx[k],y=j+dy[k],tt=ID(x,y); 102 if (x<1||y<1||x>n||y>m) continue; 103 ins(t,tt,1); 104 } 105 } 106 } 107 int ans=Max_flow(st,ed); 108 ans=(n-1)*m+(m-1)*n-ans; 109 printf("Case %d: %d\n",kase,ans); 110 } 111 return 0; 112 }