【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 }

 

posted @ 2016-11-13 20:11  konjac蒟蒻  阅读(307)  评论(0编辑  收藏  举报