1. 程式人生 > >【HDU4859】 海岸線(網路流-最小割)

【HDU4859】 海岸線(網路流-最小割)

Problem Description 歡迎來到珠海!

由於土地資源越來越緊張,使得許多海濱城市都只能依靠填海來擴充套件市區以求發展。作為Z市的決策人,在仔細觀察了Z市地圖之後,你準備通過填充某些海域來擴充套件Z市的海岸線到最長,來吸引更多的遊客前來旅遊度假。為了簡化問題,假設地圖為一個N*M的格子,其中一些是陸地,一些是可以填充的淺海域,一些是不可填充的深海域。這裡定義海岸線的長度為一個聯通塊陸地(可能包含淺海域填充變為的陸地)的邊緣長度,兩個格子至少有一個公共邊,則視為聯通。

值得注意的是,這裡Z市的陸地區域可以是不聯通的,並且整個地圖都處在海洋之中,也就是說,Z市是由一些孤島組成的,比如像,夏威夷?

你的任務是,填充某些淺海域,使得所有島嶼的海岸線之和最長。 Input
輸入第一行為T,表示有T組測試資料。
每組資料以兩個整數N和M開始,表示地圖的規模。接下來的N行,每一行包含一個長度為M的字串,表示地圖,‘.’表示陸地,’E’表示淺海域,’D’表示深海域。

[Technical Specification]

1. 1 <= T <= 100
2. 1 <= N, M <= 47 Output 對每組資料,先輸出為第幾組資料,然後輸出最長的海岸線長度。 Sample Input 3 2 2 EE EE 3 3 EEE .E. EEE 3 3 EEE DED EEE Sample Output
Case 1: 8 Case 2: 16 Case 3: 20 Hint 對於第三組樣例,一種可行方案是: .E. D.D .E. 這樣5個孤立小島的海岸線總長為4 * 5 = 20。
【分析】   網路流構圖。   最小割定理:最小割等於最大流。

因為E有兩個選擇D或者.   其實就暗含了最小割的模型。 最小割的話,就是一部分分到源點一側,一部分分到匯點一側。

如果把源點分在一起當成是.   和匯點分在一起當成是D.  那麼建圖的時候,相鄰的建流量為1的邊。 如果這個點本來是. 那個連匯點是INF,本來是D的,連源點是INF。

如果是這種建圖的話,最小割求出來的最小周長。

我們需要的最大周長。

稍微轉化下。 我們希望相鄰格子不同的最多,其實就是要相鄰格子相同的最少。

所以用最小割來求相鄰格子相同的最小值,然後總相鄰數減掉這個就是答案了。

建圖方法就是一開始進行奇偶染色。相當於對於點(x,y)

如果(x+y)%2 == 0 那麼當成這個格子是 . 的,和源點分在一起。

如果(x+y)%2 == 1 那麼當成這個格子是 D 的,和匯點分在一起。

相鄰兩點都建邊。

這樣建圖的話,如果在源點一側的跑到了匯點一側,那麼就相當於這個點從.變到D, 自然相同的數量要減少了、

匯點一側的跑到了源點一側,那麼就相當於這個點從D變成了.

建圖的時候,如果(x+y)%2==0 && 這個點本來就是D  或者 (x+y)%2 == 1 && 這個點本來就是.     那麼這個點必須和匯點在一起,就把這個點和源點連INF的邊。 相反情況類似處理。

這樣建圖出來的最小割,一定就是相鄰格子是同一類的最小數量。總相鄰減掉這個值就是答案了。

  即如圖所示:   對於右邊綠色的圖的情況的(1,1)點和(1,2)點連邊如圖所示。(藍色為邊的編號,橙色為流量)   上面棕色點為(1,1) 下面棕色點為(1,2)     割邊1表示點(1,1)為陸,割邊2表示點(1,1)為海
    割邊4表示點(1,2)為海,割邊5表示點(1,2)為陸   因為有雙向邊3,所以當兩點同為陸或者海,必須把3號邊也割了(花費1),圖才能分割開。   一開始假設所有有可能的(即不確定的)都是海岸線,建圖跑最小割即可。   注意相鄰兩點表示陸海的時候要反過來。   網路流之前打的模版有點慢,導致我一直TLE,這樣做會快一點: AC程式碼如下:
  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<queue>
  7 using namespace std;
  8 #define Maxn 4010
  9 #define Maxm 4010*4
 10 #define INF 0xfffffff
 11 
 12 char s[60];
 13 
 14 int map[60][60];
 15 int dx[6]={0,-1,0,0,1},
 16     dy[6]={0,0,-1,1,0};
 17 int num[60][60];
 18 int s1[60][60],s2[60][60];
 19 
 20 struct node
 21 {
 22     int x,y,f,o,next;
 23 }t[Maxm*2];int len;
 24 
 25 int st,ed;
 26 int dis[Maxn],first[Maxn];
 27 
 28 int mymin(int x,int y) {return x<y?x:y;}
 29 
 30 void ins(int x,int y,int f)
 31 {
 32     if(f==0) return; 
 33     t[++len].x=x;t[len].y=y;t[len].f=f;
 34     t[len].next=first[x];first[x]=len;t[len].o=len+1;
 35     t[++len].x=y;t[len].y=x;t[len].f=0;
 36     t[len].next=first[y];first[y]=len;t[len].o=len-1;
 37 }
 38 
 39 queue<int > q;
 40 bool bfs()
 41 {
 42     while(!q.empty()) q.pop();
 43     memset(dis,-1,sizeof(dis));
 44     dis[st]=0;q.push(st);
 45     while(!q.empty())
 46     {
 47         int x=q.front();q.pop();
 48         for(int i=first[x];i;i=t[i].next) if(t[i].f>0)
 49         {
 50             int y=t[i].y;
 51             if(dis[y]==-1)
 52             {
 53                 dis[y]=dis[x]+1;
 54                 q.push(y);
 55             }
 56         }
 57     }
 58     if(dis[ed]!=-1) return 1;
 59     return 0;
 60 }
 61 
 62 int ffind(int x,int mmin)
 63 {
 64     if(x==ed) return mmin;
 65     int r=0;
 66     for(int i=first[x];i;i=t[i].next) if(dis[t[i].y]==dis[x]+1 && t[i].f>0)
 67     {
 68         int y=t[i].y,a=mymin(t[i].f,mmin-r);
 69         a=ffind(y,a);r+=a;
 70         t[i].f-=a;
 71         t[t[i].o].f+=a;
 72     }
 73     if(r==0) dis[x]=-1;
 74     return r;
 75 }
 76 
 77 int min_cut()
 78 {
 79     int a,ans=0;
 80     while(bfs()) ans+=ffind(st,INF);
 81     return ans;
 82 }
 83 
 84 int main()
 85 {
 86     int T,kase=0,ans;
 87     scanf("%d",&T);
 88     while(T--)
 89     {
 90         int n,m;
 91         scanf("%d%d",&n,&m);
 92         for(int i=1;i<=n;i++)
 93         {
 94             scanf("%s",s);
 95             for(int j=0;j<m;j++)
 96             {
 97                 if(s[j]=='E') map[i][j+1]=0;
 98                 else if(s[j]=='.') map[i][j+1]=1;
 99                 else map[i][j+1]=2;
100             }
101         }
102         
103         int ans=2*n*m+n+m;
104         for(int i=0;i<=m+1;i++) map[0][i]=2,map[n+1][i]=2;
105         for(int i=0;i<=n+1;i++) map[i][0]=2,map[i][m+1]=2;
106         
107         memset(s1,0,sizeof(s1));
108         memset(s2,0,sizeof(s2));
109         for(int i=1;i<=n;i++)
110          for(int j=1;j<=m;j++) if(map[i][j]!=0)
111          {
112              int now=i*(m+2)+j;
113              for(int k=1;k<=4;k++)
114              {
115                  int nx=i+dx[k],ny=j+dy[k];
116                  if(map[i][j]==1) s1[nx][ny]++;
117                  if(map[i][j]==2) s2[nx][ny]++;
118                  if((nx==0||ny==0||nx==n+1||ny==m+1)&&map[i][j]==2) ans--;
119                  else if(map[nx][ny]!=0&&map[nx][ny]==map[i][j]&&k<=2)    ans--;
120              }
121          }
122         for(int i=1;i<=m;i++) s2[1][i]++,s2[n][i]++;
123         for(int i=1;i<=n;i++) s2[i][1]++,s2[i][m]++;
124         memset(first,0,sizeof(first));
125         len=0;int cnt=2;
126         st=1,ed=2;
127         for(int i=1;i<=n;i++)
128          for(int j=1;j<=m;j++) if(map[i][j]==0)
129          {
130              int now=++cnt;num[i][j]=cnt;
131              if((i+j)%2==0) {ins(now,ed,s2[i][j]);ins(st,now,s1[i][j]);}
132              else {ins(now,ed,s1[i][j]);ins(st,now,s2[i][j]);}
133              for(int k=1;k<=2;k++)
134              {
135                  int nx=i+dx[k],ny=j+dy[k];
136                  if(nx<1||nx>n||ny<1||ny>m) continue;
137                  if(map[nx][ny]!=0) continue;
138                  int d=num[nx][ny];
139                  ins(now,d,1);ins(d,now,1);
140              }
141          }
142         ans-=min_cut();
143         printf("Case %d: %d\n",++kase,ans);
144     }
145     return 0;
146 }
[HDU4859]

2016-05-17 16:42:42