HDU4859 海岸线(最小割)
2016-04-05 20:10
399 查看
题目大概就是说一个n*m的地图,地图上每一块是陆地或浅海域或深海域,可以填充若干个浅海域使其变为陆地,问能得到的最长的陆地海岸线是多少。
也是很有意思的一道题。
一开始想歪了,想着,不考虑海岸线重合的情况那海岸线长度就是所有非深海域的个数*4,而每一块要嘛是陆地要嘛不是陆地,如果浅海域不变成陆地那么花费4,而对于重合情况花费是2,那样似乎是经典的二者选其一的最小割模型,最后的答案就是所有非深海域的个数*4-最小割。
不过,那个经典的模型是二者选法不同有额外花费,而这儿是二者同时是陆地有额外花费,这个额外花费指的是重合花费2——入手点也是这儿——
对地图黑白染色,两色的点分别作X部Y部,X部向其相邻的Y部点连容量2的边!
源点向X部是陆地的点连容量INF的边,是浅海域的点连容量4的边,是深海域的点连容量0的边
Y部是陆地的点向汇点连容量INF的边,是浅海域的点连容量4的边,是深海域的点连容量0的边
如此建容量网络计算最小割就是要求的最少的花费了,画画图就知道了。
也是很有意思的一道题。
一开始想歪了,想着,不考虑海岸线重合的情况那海岸线长度就是所有非深海域的个数*4,而每一块要嘛是陆地要嘛不是陆地,如果浅海域不变成陆地那么花费4,而对于重合情况花费是2,那样似乎是经典的二者选其一的最小割模型,最后的答案就是所有非深海域的个数*4-最小割。
不过,那个经典的模型是二者选法不同有额外花费,而这儿是二者同时是陆地有额外花费,这个额外花费指的是重合花费2——入手点也是这儿——
对地图黑白染色,两色的点分别作X部Y部,X部向其相邻的Y部点连容量2的边!
源点向X部是陆地的点连容量INF的边,是浅海域的点连容量4的边,是深海域的点连容量0的边
Y部是陆地的点向汇点连容量INF的边,是浅海域的点连容量4的边,是深海域的点连容量0的边
如此建容量网络计算最小割就是要求的最少的花费了,画画图就知道了。
#include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; #define INF (1<<30) #define MAXN 2555 #define MAXM 2555*2555 struct Edge{ int v,cap,flow,next; }edge[MAXM]; int vs,vt,NE,NV; int head[MAXN]; void addEdge(int u,int v,int cap){ edge[NE].v=v; edge[NE].cap=cap; edge[NE].flow=0; edge[NE].next=head[u]; head[u]=NE++; edge[NE].v=u; edge[NE].cap=0; edge[NE].flow=0; edge[NE].next=head[v]; head[v]=NE++; } int level[MAXN]; int gap[MAXN]; void bfs(){ memset(level,-1,sizeof(level)); memset(gap,0,sizeof(gap)); level[vt]=0; gap[level[vt]]++; queue<int> que; que.push(vt); while(!que.empty()){ int u=que.front(); que.pop(); for(int i=head[u]; i!=-1; i=edge[i].next){ int v=edge[i].v; if(level[v]!=-1) continue; level[v]=level[u]+1; gap[level[v]]++; que.push(v); } } } int pre[MAXN]; int cur[MAXN]; int ISAP(){ bfs(); memset(pre,-1,sizeof(pre)); memcpy(cur,head,sizeof(head)); int u=pre[vs]=vs,flow=0,aug=INF; gap[0]=NV; while(level[vs]<NV){ bool flag=false; for(int &i=cur[u]; i!=-1; i=edge[i].next){ int v=edge[i].v; if(edge[i].cap!=edge[i].flow && level[u]==level[v]+1){ flag=true; pre[v]=u; u=v; //aug=(aug==-1?edge[i].cap:min(aug,edge[i].cap)); aug=min(aug,edge[i].cap-edge[i].flow); if(v==vt){ flow+=aug; for(u=pre[v]; v!=vs; v=u,u=pre[u]){ edge[cur[u]].flow+=aug; edge[cur[u]^1].flow-=aug; } //aug=-1; aug=INF; } break; } } if(flag) continue; int minlevel=NV; for(int i=head[u]; i!=-1; i=edge[i].next){ int v=edge[i].v; if(edge[i].cap!=edge[i].flow && level[v]<minlevel){ minlevel=level[v]; cur[u]=i; } } if(--gap[level[u]]==0) break; level[u]=minlevel+1; gap[level[u]]++; u=pre[u]; } return flow; } int dx[]={0,1}; int dy[]={1,0}; int main(){ char map[55][55]; int t,n,m; scanf("%d",&t); for(int cse=1; cse<=t; ++cse){ scanf("%d%d",&n,&m); int tot=0; for(int i=0; i<n; ++i){ for(int j=0; j<m; ++j){ scanf(" %c",&map[i][j]); if(map[i][j]!='D') ++tot; } } tot<<=2; vs=n*m; vt=vs+1; NV=vt+1; NE=0; memset(head,-1,sizeof(head)); for(int i=0; i<n; ++i){ for(int j=0; j<m; ++j){ if(i+j&1){ if(map[i][j]=='.') addEdge(vs,i*m+j,INF); else if(map[i][j]=='E') addEdge(vs,i*m+j,4); for(int k=0; k<2; ++k){ int nx=i+dx[k],ny=j+dy[k]; if(nx<0 || nx>=n || ny<0 || ny>=m) continue; addEdge(i*m+j,nx*m+ny,2); } }else{ if(map[i][j]=='.') addEdge(i*m+j,vt,INF); else if(map[i][j]=='E') addEdge(i*m+j,vt,4); for(int k=0; k<2; ++k){ int nx=i+dx[k],ny=j+dy[k]; if(nx<0 || nx>=n || ny<0 || ny>=m) continue; addEdge(nx*m+ny,i*m+j,2); } } } } printf("Case %d: %d\n",cse,tot-ISAP()); } return 0; }
相关文章推荐
- codeforces_620D. Professor GukiZ and Two Arrays
- 程序运行时的内存空间分布
- Web Server 与 App Server 的区别
- 134. Gas Station
- iOS应用启动页的渐变效果
- 【Android】8、活动的基本用法(一)
- weka
- 2014 小朋友排队(树状数组+逆序数)
- mysql
- ZMY_工厂模式
- python get方法
- 1001. A+B Format
- ccf 送货
- Ubuntu查看MySQL的数据库data存放路径
- 解析XML
- java编程的注意事项
- XTU1233 Coins
- RecyclerView中item的选中效果
- Guava学习笔记:Google Guava 类库简介
- NSString与NSMutableString的基本使用