您的位置:首页 > 其它

hdu 4859 海岸线 Bestcoder Round 1

2017-01-06 17:10 369 查看

http://acm.hdu.edu.cn/showproblem.php?pid=4859

题目大意:

  在一个矩形周围都是海,这个矩形中有陆地,深海和浅海。浅海是可以填成陆地的。

  求最多有多少条方格线满足两侧分别是海洋和陆地

这道题很神

首先考虑一下,什么情况下能够对答案做出贡献

就是相邻的两块不一样的时候

这样我们可以建立最小割模型,可是都说是最小割了

无法求出最大的不相同的东西

所以我们考虑转化,用总的配对数目 - 最小的相同的对数

至于最小的相同的对数怎么算呢?

我们考虑这样的构造方法:

 把整个棋盘黑白染色,我们想要所有的黑格子都是陆地,所有的白格子都是海洋

 但是天不尽人意

 输入数据肯定不会给你做出这种东西,所以会出现各种各样的不符的格子

 所以我们把所有符合的格子和不符的格子拿开

 把所有的与其所在的集合相符的格子放到一个集合中(记为S1)

 把所有的与其所在的集合不相符的格子放到另一个集合中(记为S2)

 把剩下的没有被分到任何集合的格子,也就是所有的E格,放到另一个集合中(记为S3)

 然后我们在所有相邻且所在集合不同(S1,S2,S3)点之间连上双向边

 这时图中存在的任意一条从S -> T的可行流都一定经过S1,S2集合中两个形式相同的格子

 这时候还有可能经过若干S3中的点

 那么这时候就代表我们让这些S3中的点和S1,S2中我们选择的点的形式相同

 这就是最小的相同对数了

 所以ans = tot - dinic()其中tot = (n-1)*m + (m-1)*n

 做完了题了我们定义一下每一条边的含义:

  一条边一定是条双向边

  这条边代表的含义就是这条边连接的两个点必须相同才有可能对答案做出贡献

  而我们知道,一条边连接的两个格子一定在最初的黑白染色中属于不同的颜色

  如果他们颜色相同的话,一定不会被一起分到s1或s2集合中

  并且一定会被分散到S1和S2集合中

  所以我们不能连接相同集合中的边,却能连接不同集合中的边

但是连接的话从数值上来说是不变的,可是本人认为意义上解释不通

网上的其他题解都是没有关心是否在同一个集合内部,都进行了连边

不过本人太弱,无论如何都想不通集合内部的边的意义,所以本人认为那条边不应该存在,是没有意义的。

如果真的是本苣太弱了,还请各位dalao高台贵手。。

Code : 删去了集合内部的边,依然AC

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
inline int cat_max(const int &a,const int &b){return a>b ? a:b;}
inline int cat_min(const int &a,const int &b){return a<b ? a:b;}
const int maxn = 501;
const int maxnode = 30100;
const int maxedge = 210045;
const int inf = 0x3f3f3f3f;
struct Edge{
int to,next,cap;
}G[maxedge<<1];
int head[maxnode],cnt=1;
void add(int u,int v,int c){
G[++cnt].to = v;
G[cnt].next = head[u];
G[cnt].cap = c;
head[u] = cnt;
}
void insert(int u,int v,int c){
add(u,v,c);add(v,u,0);
}
int dis[maxnode],q[maxnode],l,r;
int S,T,cur[maxnode];
#define v G[i].to
bool bfs(){
memset(dis,-1,sizeof dis);
dis[S] = 0;l = 0;r = -1;
q[++r] = S;
while(l <= r){
int u = q[l++];
for(int i = head[u];i;i=G[i].next){
if(dis[v] == -1 && G[i].cap){
dis[v] = dis[u] + 1;
q[++r] = v;
}
}
}return dis[T] != -1;
}
int dfs(int u,int f){
if(u == T || f == 0) return f;
int ret = 0;
for(int &i = cur[u];i;i=G[i].next){
if(dis[v] == dis[u] + 1){
int x = dfs(v,cat_min(G[i].cap,f));
ret += x;f -= x;
G[i].cap -= x;G[i^1].cap += x;
if(f == 0) break;
}
}if(ret == 0) dis[u] = -1;
return ret;
}
#undef v
inline int dinic(){
int ret = 0;
while(bfs()){
memcpy(cur,head,sizeof head);
ret += dfs(S,inf);
}return ret;
}
int tag[maxnode];
inline void init(){
memset(head,0,sizeof head);
memset(tag,0,sizeof tag);
cnt = 1;S = maxnode - 5;T = S+1;
}
char map[maxn][maxn],ch;
#define f(x,y) ((x-1)*m+y)
int dx[] = {0,0,0,1,-1};
int dy[] = {0,1,-1,0,0};
int main(){
int tim;read(tim);
for(int Case = 1;Case <= tim;++Case){
init();
int n,m;read(n);read(m);
for(int i=1;i<=n+2;++i) map[i][1] = map[i][m+2] = 'D';
for(int i=1;i<=m+2;++i) map[1][i] = map[n+2][i] = 'D';
for(int i=2;i<=n+1;++i){
for(int j=2;j<=m+1;++j){
while(ch=getchar(),ch<'!');
map[i][j] = ch;
}
}n += 2;m += 2;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
if((i+j)&1){
if(map[i][j] == '.') insert(S,f(i,j),inf),tag[f(i,j)] = 1;
if(map[i][j] == 'D') insert(f(i,j),T,inf),tag[f(i,j)] = 2;
}else{
if(map[i][j] == 'D') insert(S,f(i,j),inf),tag[f(i,j)] = 1;
if(map[i][j] == '.') insert(f(i,j),T,inf),tag[f(i,j)] = 2;
}
for(int k=1;k<=4;++k){
int nx = i + dx[k];
int ny = j + dy[k];
if(nx < 1 || ny < 1 || nx > n || ny > m) continue;
if(tag[f(i,j)] == 0 || tag[f(nx,ny)] == 0) insert(f(i,j),f(nx,ny),1);
else if(tag[f(i,j)] != tag[f(nx,ny)]) insert(f(i,j),f(nx,ny),1);
}
}
}
int ans = (2*n*m) - (n+m) - dinic();
printf("Case %d: %d\n",Case,ans);
}
getchar();getchar();
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: