您的位置:首页 > 其它

【bzoj4213】【贪吃蛇】【有上下界的费用流】

2016-07-04 22:16 405 查看

Description

 最近lwher迷上了贪吃蛇游戏,在玩了几天却从未占满全地图的情况下,他不得不承认自己是一个弱菜,只能改去开发一款更弱的贪吃蛇游戏。
在开发的过程中,lwher脑洞大开,搞了一个多条蛇的模式。但由于这种模式太难操作,于是他只好改变游戏的玩法,稍微变化一下游戏目标。
新的游戏是这样的:
一些蛇覆盖了一个网格。每个格子要么是一个障碍物,要么是蛇的一部分。每条蛇占据了一条折线(拐角处只能水平和竖直连接),且只是占据两个格子。蛇与蛇之间不能重叠,蛇也不会与自己重叠。每条蛇还必须满足以下两个条件中的一个:
     1、两个端点所在的格子在网格的边界。
     2、蛇构成一个环,即两个端点相邻(垂直或水平,不能斜着),至少要占据4个格子(否则没法形成环)。
给定一个网格,用r x c的字符矩阵描述:‘#’代表障碍物,‘.’代表空地。在满足前面所述的条件下覆盖所有空地,并使得端点在网格边界(即不构成环)的蛇尽量少。(如果一条蛇既构成环,又是端点在边界,那么不计入答案)
     例如,以下网格:

 


可以由下面三种方案覆盖。还有其他的方案,但是没法仅用一条不构成环的蛇就覆盖整个网络的方案。



 

给定一个网络的描述,输出最少需要多少条不构成环的蛇来覆盖这个网格。如果不存在能够覆盖网格的方案,输出-1。

Input

一个字符矩阵,行数和列数不超过12。输入文件中没有多余的空白字符,每行之后都有换行符。

Output

输出满足题目要求的那个整数。

Sample Input

......

.#.##.

.#....

....#.

.##.#.

......

Sample Output

2

题解:

考虑一条不构成环的蛇,除了头尾之外的点,每个点都与两个点相连.

而环形蛇则所有点都与两个点相连.

所以我们对矩阵黑白染色.建立源点s,汇点t.

s向所有白点连容量为2,费用为0的边,表示这个点需要与两个点相连.

所有黑点向t连容量为2,费用为0的边,表示两个点需要与这个点相连.

这里的容量为2是指容量必须为2,需要上下界来限定.

每个白点向周围的黑点连容量为1,费用为0的边,表示这个点可以和周围的点形成蛇.

这里的容量并不要求一定是1,不需要用上下界来限定

每个边界上的白点向t连容量为1,费用为1的边,表示形成了一条不成环的蛇.

s向每个边界上的黑点连容量为1,费用为1的边,表示形成了一条不成环的蛇.

然后用有源有汇有上下界的费用流处理即可.

注意每条蛇会在头和尾各算一次,所以最后答案需要除2.

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 200
#define M 2000
#define inf 210000000
using namespace std;
int point
,next[M<<1],ans,m,n=1,cnt=1,d
,s,t,S,T,q[N*30],f
;
int cur
,pre
,gap
,dis
,dx[]={1,0,-1,0},dy[]={0,1,0,-1};
char ch

;
struct use{int st,en,v,c;}e[M<<1];
int cal(int x,int y){return (x-1)*m+y;}
void add(int x,int y,int v,int c){
//cout<<x<<' '<<y<<' '<<v<<' '<<c<<endl;
next[++cnt]=point[x];point[x]=cnt;
e[cnt].st=x;e[cnt].en=y;e[cnt].v=v;e[cnt].c=c;
next[++cnt]=point[y];point[y]=cnt;
e[cnt].st=y;e[cnt].en=x;e[cnt].v=0;e[cnt].c=-c;
}
bool spfa(){
for (int i=1;i<=T;i++) dis[i]=inf;
memset(f,0,sizeof(f));
int l(0),r(1);
q[r]=S;dis[S]=0;f[S]=1;
while (l<r){
int u=q[++l];f[u]=0;
for (int i=point[u];i;i=next[i])
if (e[i].v&&dis[e[i].en]>dis[u]+e[i].c){
dis[e[i].en]=dis[u]+e[i].c;
pre[e[i].en]=i;
if (!f[e[i].en]){
f[e[i].en]=1;
q[++r]=e[i].en;
}
}
}
return dis[T]!=inf;
}
void solve(){
int mn=inf;
for (int i=T;i!=S;i=e[pre[i]].st) mn=min(mn,e[pre[i]].v);
for (int i=T;i!=S;i=e[pre[i]].st){
e[pre[i]].v-=mn;e[pre[i]^1].v+=mn;ans+=e[pre[i]].c*mn;
}
}
bool check(){
for (int i=point[S];i;i=next[i])
if (e[i].v) return 0;
return 1;
}
void build(){
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (ch[i][j]=='.'){
if (i+j&1){
if (i==1||j==1||i==n||j==m) add(cal(i,j),t,1,1);
d[s]-=2;d[cal(i,j)]+=2;
for (int k=0;k<4;k++){
int xx=i+dx[k],yy=j+dy[k];
if (xx<1||xx>n||yy<1||yy>m||ch[xx][yy]=='#') continue;
add(cal(i,j),cal(xx,yy),1,0);
}
}
else{
if (i==1||j==1||i==n||j==m) add(s,cal(i,j),1,1);
d[t]+=2;d[cal(i,j)]-=2;
}
}
for (int i=1;i<=t;i++)
if (d[i]>0) add(S,i,d[i],0);
else if (d[i]<0)add(i,T,-d[i],0);
add(t,s,inf,0);
}
int main(){
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
while (scanf("%s",ch
+1)!=EOF) n++;n--;
m=strlen(ch
+1);
s=n*m+1;t=s+1;S=t+1;T=S+1;
build();
while (spfa()) solve();
if (!check()){
cout<<-1<<endl;
return 0;
}
else cout<<ans/2<<endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: