http://acm.hdu.edu.cn/showproblem.php?pid=4859
题意:
欢迎来到珠海!
由于土地资源越来越紧张,使得许多海滨城市都只能依靠填海来扩展市区以求发展。作为Z市的决策人,在仔细观察了Z市地图之后,你准备通过填充某些海域来扩展Z市的海岸线到最长,来吸引更多的游客前来旅游度假。为了简化问题,假设地图为一个N*M的格子,其中一些是陆地,一些是可以填充的浅海域,一些是不可填充的深海域。这里定义海岸线的长度为一个联通块陆地(可能包含浅海域填充变为的陆地)的边缘长度,两个格子至少有一个公共边,则视为联通。
值得注意的是,这里Z市的陆地区域可以是不联通的,并且整个地图都处在海洋之中,也就是说,Z市是由一些孤岛组成的,比如像,夏威夷?
你的任务是,填充某些浅海域,使得所有岛屿的海岸线之和最长。
思路:
这道题目的话和最大独立点权是比较相似的。
首先考虑一个格子的情况,它的海岸线长度之和就是它周围有多少海域,如果它四条边都是海域,那么它的海岸线长度之和就是4,如果周围有陆地则会相应的减少。
那么其实这道题目就是要我们求最大相邻的'D'和'.' 的总对数!!
先在格子周围加上一圈'D',先将这个图分成一个二分图,左边为X集,右边为Y集(X与源点相连,表示陆地,Y与汇点相连,表示海域),接下来分析每个格子:
1、若相邻则连边,容量1。
2、若当前点在地图上是 . 但是却被分到了Y集,或者当前点是 D ,却被分到了X集,就和源点连一条INF的边。
3、若当前点在地图上是 . 并且被分到了X集,或者当前点是 D ,被分到了Y集,就和汇点连一条INF的边。
所以只有 . --> . 或者 D --> D ,也就是类型相同的,才能从源流向汇。此时需要减少1的海岸线,因为不是'.'与'D'相邻。最小割求出最小的相同格子相邻的对数。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<stack> 7 #include<queue> 8 #include<cmath> 9 #include<map> 10 #include<set> 11 using namespace std; 12 typedef long long ll; 13 typedef pair<int,int> pll; 14 const int INF = 0x3f3f3f3f; 15 const int maxn=1e6+5; 16 17 int n, m; 18 int mp[60][60]; 19 20 int dx[]={0,0,1,-1}; 21 int dy[]={1,-1,0,0}; 22 23 struct Edge 24 { 25 int from,to,cap,flow; 26 Edge(int u,int v,int w,int f):from(u),to(v),cap(w),flow(f){} 27 }; 28 29 struct Dinic 30 { 31 int n,m,s,t; 32 vector<Edge> edges; 33 vector<int> G[maxn]; 34 bool vis[maxn]; 35 int cur[maxn]; 36 int d[maxn]; 37 38 void init(int n) 39 { 40 this->n=n; 41 for(int i=0;i<n;++i) G[i].clear(); 42 edges.clear(); 43 } 44 45 void AddEdge(int from,int to,int cap) 46 { 47 edges.push_back( Edge(from,to,cap,0) ); 48 edges.push_back( Edge(to,from,0,0) ); 49 m=edges.size(); 50 G[from].push_back(m-2); 51 G[to].push_back(m-1); 52 } 53 54 bool BFS() 55 { 56 queue<int> Q; 57 memset(vis,0,sizeof(vis)); 58 vis[s]=true; 59 d[s]=0; 60 Q.push(s); 61 while(!Q.empty()) 62 { 63 int x=Q.front(); Q.pop(); 64 for(int i=0;i<G[x].size();++i) 65 { 66 Edge& e=edges[G[x][i]]; 67 if(!vis[e.to] && e.cap>e.flow) 68 { 69 vis[e.to]=true; 70 d[e.to]=d[x]+1; 71 Q.push(e.to); 72 } 73 } 74 } 75 return vis[t]; 76 } 77 78 int DFS(int x,int a) 79 { 80 if(x==t || a==0) return a; 81 int flow=0, f; 82 for(int &i=cur[x];i<G[x].size();++i) 83 { 84 Edge &e=edges[G[x][i]]; 85 if(d[e.to]==d[x]+1 && (f=DFS(e.to,min(a,e.cap-e.flow) ) )>0) 86 { 87 e.flow +=f; 88 edges[G[x][i]^1].flow -=f; 89 flow +=f; 90 a -=f; 91 if(a==0) break; 92 } 93 } 94 return flow; 95 } 96 97 int Maxflow(int s,int t) 98 { 99 this->s=s; this->t=t; 100 int flow=0; 101 while(BFS()) 102 { 103 memset(cur,0,sizeof(cur)); 104 flow +=DFS(s,INF); 105 } 106 return flow; 107 } 108 }DC; 109 110 int main() 111 { 112 //freopen("in.txt", "r", stdin); 113 char s[60]; 114 int kase=0; 115 int T; 116 scanf("%d",&T); 117 while(T--) 118 { 119 memset(mp,0,sizeof(mp)); 120 scanf("%d%d",&n,&m); 121 for(int i=1;i<=n;i++) 122 { 123 scanf("%s",s); 124 for(int j=0;j<m;j++) 125 { 126 if(s[j]=='E') mp[i][j+1]=2; 127 else if(s[j]=='.') mp[i][j+1]=1; 128 } 129 } 130 int src=0,dst=(n+2)*(m+2)+1; 131 DC.init(dst+1); 132 for(int i=0;i<=n+1;i++) 133 { 134 for(int j=0;j<=m+1;j++) 135 { 136 if((i+j)%2==0) 137 { 138 if(mp[i][j]==1) DC.AddEdge(i*(m+2)+j+1,dst,INF); 139 else if(mp[i][j]==0) DC.AddEdge(src,i*(m+2)+j+1,INF); 140 } 141 else 142 { 143 if(mp[i][j]==0) DC.AddEdge(i*(m+2)+j+1,dst,INF); 144 else if(mp[i][j]==1) DC.AddEdge(src,i*(m+2)+j+1,INF); 145 } 146 for(int k=0;k<4;k++) 147 { 148 int x=i+dx[k]; 149 int y=j+dy[k]; 150 if(x<0 || x>n+1 || y<0 || y>m+1) continue; 151 DC.AddEdge(i*(m+2)+j+1,x*(m+2)+y+1,1); 152 } 153 } 154 } 155 int ans=DC.Maxflow(src,dst); 156 printf("Case %d: %d ",++kase,(n+1)*(m+2)+(n+2)*(m+1)-ans); 157 } 158 return 0; 159 }