您的位置:首页 > 其它

bzoj千题计划135:bzoj1066: [SCOI2007]蜥蜴

2017-12-14 19:49 260 查看
http://www.lydsy.com/JudgeOnline/problem.php?id=1066

每个柱子拆成两个点 i<<1,i<<1|1,之间连流量为高度的边

如果第i根柱子有蜥蜴,S向i<<1连边,流量为1

如果第i根柱子能跳出去,i<<1|1向T连边,流量为inf

如果第i根柱子能跳到第j根柱子,i<<1|1向j<<1连边,流量为inf

至于每根柱子每个时刻只能有一个蜥蜴,不需要管,总可以通过先后顺序调整成满足条件

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 900
#define M 21500

const int inf=1e9;

char s[21];
int mp[21][21];

int cnt;
int id[21][21];

int tot=1;
int front
,nxt[M<<1],to[M<<1],val[M<<1],from[M<<1];
int lev
,num
;
int path
;
int cur
;

int src,decc;

void add(int u,int v,int w)
{
to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; from[tot]=u; val[tot]=w;
to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; from[tot]=v; val[tot]=0;
//cout<<u<<' '<<v<<' '<<w<<'\n';
}

bool bfs()
{
queue<int>q;
for(int i=src;i<=decc;++i) lev[i]=decc;
q.push(decc);
lev[decc]=0;
int now,t;
while(!q.empty())
{
now=q.front();
q.pop();
for(int i=front[now];i;i=nxt[i])
{
t=to[i];
if(lev[t]==decc && val[i^1])
{
lev[t]=lev[now]+1;
q.push(t);
}
}
}
return lev[src]!=decc;
}

int augment()
{
int now=decc,flow=inf;
int i;
while(now!=src)
{
i=path[now];
flow=min(flow,val[i]);
now=from[i];
}
now=decc;
while(now!=src)
{
i=path[now];
val[i]-=flow;
val[i^1]+=flow;
now=from[i];
}
return flow;
}

int isap()
{
int flow=0;
if(!bfs()) return 0;
memset(num,0,sizeof(num));
for(int i=src;i<=decc;++i) num[lev[i]]++,cur[i]=front[i];
int now=src,t;
while(lev[src]<decc)
{
if(now==decc)
{
flow+=augment();
now=src;
}
bool advanced=false;
for(int i=cur[now];i;i=nxt[i])
{
t=to[i];
if(lev[t]==lev[now]-1 && val[i])
{
advanced=true;
path[t]=i;
cur[now]=i;
now=t;
break;
}
}
if(!advanced)
{
int mi=decc;
for(int i=front[now];i;i=nxt[i])
if(val[i]) mi=min(mi,lev[to[i]]);
if(!--num[lev[now]]) break;
num[lev[now]=mi+1]++;
cur[now]=front[now];
if(now!=src) now=from[path[now]];
}
}
return flow;
}

int main()
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;++i)
{
scanf("%s",s+1);
for(int j=1;j<=m;++j)
{
mp[i][j]=s[j]-'0';
if(mp[i][j]) id[i][j]=++cnt;
}
}
src=1; decc=(cnt<<1|1)+1;
int x,y;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
if(!mp[i][j]) continue;
add(id[i][j]<<1,id[i][j]<<1|1,mp[i][j]);
for(int r=1;r<=n;++r)
for(int c=1;c<=m;++c)
{
if(!mp[r][c] || (r==i && c==j)) continue;
if((r-i)*(r-i)+(c-j)*(c-j)<=k*k) add(id[i][j]<<1|1,id[r][c]<<1,mp[i][j]);
//if(abs(r-i)+abs(c-j)<=k) add(id[i][j]<<1|1,id[r][c]<<1,inf);
}
if(i<=k || j<=k || n-i<k || m-j<k) add(id[i][j]<<1|1,decc,inf);
}
int sum=0;
for(int i=1;i<=n;++i)
{
scanf("%s",s+1);
for(int j=1;j<=m;++j)
{
if(s[j]=='L')
{
sum++;
add(src,id[i][j]<<1,1);
}
}
}
cout<<sum-isap();
}


1066: [SCOI2007]蜥蜴

Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 4407 Solved: 2245
[Submit][Status][Discuss]

Description

  在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃
到边界外。 每行每列中相邻石柱的距离为1,蜥蜴的跳跃距离是d,即蜥蜴可以跳到平面距离不超过d的任何一个石
柱上。石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减1(如果仍然落在地图内部,则到达的石柱高度不
变),如果该石柱原来高度为1,则蜥蜴离开后消失。以后其他蜥蜴不能落脚。任何时刻不能有两只蜥蜴在同一个
石柱上。

Input

  输入第一行为三个整数r,c,d,即地图的规模与最大跳跃距离。以下r行为石竹的初始状态,0表示没有石柱
,1~3表示石柱的初始高度。以下r行为蜥蜴位置,“L”表示蜥蜴,“.”表示没有蜥蜴。

Output

  输出仅一行,包含一个整数,即无法逃离的蜥蜴总数的最小值。

Sample Input

5 8 2

00000000

02000000

00321100

02000000

00000000

........

........

..LLLL..

........

........

Sample Output

1

HINT

100%的数据满足:1<=r, c<=20, 1<=d<=4
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: