HDU 4859 海岸线(最小割+最大独立点权变形)

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\n",++kase,(n+1)*(m+2)+(n+2)*(m+1)-ans);
157     }
158     return 0;
159 }
时间: 2024-08-02 06:05:23

HDU 4859 海岸线(最小割+最大独立点权变形)的相关文章

HDU 4859 海岸线 最小割

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4859 题解: 这题考察的是最小割. 我们可以这样想:海岸线的长短变化都是E引起的,我们通过把’E'变成'.'或'D'来使海岸线最大化. 我们要算海岸线就是算格子‘.'和格子'D'(在原有地图周围四面都要加’D‘)相邻的面数,要使它最大,就是要使'.'与’.':'D'与'D'相邻的面数最小,而面数最小可以用最小割来做. 现在我们先把格子上的点黑白染色,(i+j)%2==1的为A类,为0的为B类, 在

HDU 4859 海岸线(最大流最小割)

难得的中文题,就不翻译了. 输入第一行为T,表示有T组测试数据.每组数据以两个整数N和M开始,表示地图的规模.接下来的N行,每一行包含一个长度为M的字符串,表示地图,‘.’表示陆地,’E’表示浅海域,’D’表示深海域.[Technical Specification]1. 1 <= T <= 1002. 1 <= N, M <= 47 题意:假设地图为一个N*M的格子,其中一些是陆地,一些是可以填充的浅海域,一些是不可填充的深海域.这里定义海岸线的长度为一个联通块陆地(可能包含浅海

hdu 4859 海岸线 Bestcoder Round 1

http://acm.hdu.edu.cn/showproblem.php?pid=4859 题目大意: 在一个矩形周围都是海,这个矩形中有陆地,深海和浅海.浅海是可以填成陆地的. 求最多有多少条方格线满足两侧分别是海洋和陆地 这道题很神 首先考虑一下,什么情况下能够对答案做出贡献 就是相邻的两块不一样的时候 这样我们可以建立最小割模型,可是都说是最小割了 无法求出最大的不相同的东西 所以我们考虑转化,用总的配对数目 - 最小的相同的对数 至于最小的相同的对数怎么算呢? 我们考虑这样的构造方法:

HDU 3061 Battle(最小割----最大权闭合图)

题目地址:HDU 3061 多校中遇到的最小割的最大权闭合模型花了一上午时间终于看懂啦. 最大权闭合图就是将一些互相有依赖关系的点转换成图,闭合图指的是在图中的每一个点的后继点都是在图内的. 还要明白简单割的概念,就是指所有的割边都与源点或汇点相连.然后让源点与正权点相连,汇点与负权点相连,权值均为其绝对值,有依赖关系的点连一条有向边,如果a必须在b的基础上,那么就连一条a->b的有向边,权值为INF.最后用所有正权值得和减去最小割的值就是答案. 具体证明可看胡伯涛大牛的国家队集训论文<最小割

hdu 3987 求最小割条数最小

题意:    一个人要从起点  0  到达 n-1   n个点  m条路  ,我们求最少破坏路的条数使无法 从起点到达终点.题意很明显  ,求最小割条数最少,由于最小割流量虽然固定,但是其条数却不固定,可以破坏3条路,也可以破坏4条路,他们总流量相同才会出现这种情况. 题解:由于上述的情况,他们总流量相同但是条数不同,现在我们需要改变边的容量使得条数少边才是最小割,条数多的将不会是最小割. 官方题解有两种 ,我选择的是在残余网络中进行扩充流的操作,使的两个最小割不同,残余网络中,我进行所有边流量

hdu 3657 Game 最小割

首先经典的奇偶建立二分图(X,Y),对于相邻两点连边2*(X&Y),源->X连边,Y->汇连边,权值w为点权,求最小割. 考虑一条路径 源->X->Y->汇 若割边选取的是源->X,则表示选Y点不选X点, 答案为w(X+Y)-w(X) 若割边选取的是Y->,则表示选X点不选Y点, 答案为w(X+Y)-w(Y) 若割边选取的是X->Y,则表示选Y点且选X点, 答案为w(X+Y)-w( 2*(X&Y) ) 即总点权-最小割 #include<

HDU - 4289 Control (最小割 MCMF)

题目大意:有一个间谍要将一些机密文件送到目的地 现在给出间谍的初始位置和要去的目的地,要求你在间谍的必经路上将其拦获且费用最小 解题思路:最小割最大流的应用,具体可以看网络流–最小割最大流 建图的话 超级源点–起始城市,容量为INF 城市拆成两点(u, v),容量为监视该城市的代价 能连通的城市连接,容量为INF 目的地和超级汇点相连,容量为INF #include <cstdio> #include <cstring> #include <algorithm> #in

HDU 3046【最小割】

题目大意:在一个n*m的矩阵上,1代表羊,2代表狼,0代表平地,我们有长度为1的一个栅栏(不是放在格子上的,是放在格子和格子之间的空隙上的),问使用最少的栅栏,能够使得狼吃不到羊. 又学到了一招,以前一直以为建图是要先设好S点T点,在把其他的点和他们两一一相连.今天学到了原来可以在整个map上根据条件建好图,再把其中的某些目标点和源汇点相连的. 思路如下: 1.建立最小割模型: ①建立源点S,将源点S连入各个有狼的节点上,权值设定为INF,表示狼可以从任意方向出发. ②建立汇点T,将各个羊节点连

HDU 4289 Control 最小割

Control 题意:有一个犯罪集团要贩卖大规模杀伤武器,从s城运输到t城,现在你是一个特殊部门的长官,可以在城市中布置眼线,但是布施眼线需要花钱,现在问至少要花费多少能使得你及时阻止他们的运输. 题解:裸的最小割模型,最小割就是最大流,我们把点拆成2个点,然后将原点与拆点建边,流量为在城市建立眼线的费用,然后拆点为出点,原点为入点,将可以到达的城市之间建流量为无穷的边. 最后求出s 到 t的拆点的最大流 那么就是这个题目的答案了. 代码: 1 #include<bits/stdc++.h>