1066: [SCOI2007]蜥蜴
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 1963 Solved: 950
[ Submit][ Status]
Description
在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外。 每行每列中相邻石柱的距离为1,蜥蜴的跳跃距离是d,即蜥蜴可以跳到平面距离不超过d的任何一个石柱上。石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减1(如果仍然落在地图内部,则到达的石柱高度不变),如果该石柱原来高度为1,则蜥蜴离开后消失。以后其他蜥蜴不能落脚。任何时刻不能有两只蜥蜴在同一个石柱上。
Input
输入第一行为三个整数r,c,d,即地图的规模与最大跳跃距离。以下r行为石竹的初始状态,0表示没有石柱,1~3表示石柱的初始高度。以下r行为蜥蜴位置,“L”表示蜥蜴,“.”表示没有蜥蜴。
Output
输出仅一行,包含一个整数,即无法逃离的蜥蜴总数的最小值。
Sample Input
00000000
02000000
00321100
02000000
00000000
........
........
..LLLL..
........
........
Sample Output
HINT
100%的数据满足:1<=r, c<=20, 1<=d<=3
终于开刷网络流的题目,建模真是一大难点啊。此题竟然可以用网络流建模...
仔细想想还是有道理的,因为每根柱子最多跳出h(高度)个蜥蜴,这不正是网络流中的流量限制条件吗?
将每根柱子假想成一根管道,蜥蜴从一端跳入,另一端跳出。
将超级源点对每个蜥蜴所在柱子连一条边权为1的边,限制蜥蜴的流入。
将所有有高度的并且可能使蜥蜴跳出边界的柱子连向超级源点,权值为无穷大,这代表蜥蜴可以越界的个数。
将所有有高度的柱子彼此(距离小于等于d)尾部连首部,表示蜥蜴可以跳来跳去,恰好一只蜥蜴跳一下,模型中一根柱子的流量会减1,通过另一根柱子往汇点方向传递。
这真是太完美的网络流模型了!可是初学很难想到。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#define Maxn 1610
using namespace std;
const int inf=0x3f3f3f3f;
struct line{
int to,next,cap;
}p[640010];
struct point{
int x,y,w;
point(int xx,int yy,int ww):x(xx),y(yy),w(ww){}
};
vector<point> dv;
int head[Maxn]; //初始化-1
int q[Maxn]; //BFS队列
int d[Maxn]; //层次
int tot; //初始化0
int src,t; //源点,汇点
char s[30][30];
int vis[30][30];
void addedge(int a,int b,int c){
p[tot].to=b;
p[tot].next=head[a];
p[tot].cap=c;
head[a]=tot++;
}
void insert(int a,int b,int c){
addedge(a,b,c);
addedge(b,a,0);
}
bool bfs(){
memset(d,-1,sizeof d);
int s=0,e=-1;
q[++e]=src;
d[src]=0;
while(s<=e){
int u=q[s++];
for(int i=head[u];i!=-1;i=p[i].next){
int v=p[i].to;
if(d[v]==-1&&p[i].cap){
d[v]=d[u]+1;
q[++e]=v;
}
}
}
return d[t]!=-1;
}
int dfs(int u,int alpha){
if(u==t) return alpha;
int w,used=0;
for(int i=head[u];i!=-1&&used<alpha;i=p[i].next){
int v=p[i].to;
if(p[i].cap&&d[v]==d[u]+1){
w=dfs(v,min(alpha-used,p[i].cap));
used+=w;
p[i].cap-=w;
p[i^1].cap+=w;
}
}
if(!used) d[u]=-1;
return used;
}
int dinic(){
int ans=0;
src=0,t=1000;
while(bfs())
ans+=dfs(src,inf);
return ans;
}
bool dis(int i,int j,int d){
return (dv[i].x-dv[j].x)*(dv[i].x-dv[j].x)+
(dv[i].y-dv[j].y)*(dv[i].y-dv[j].y)<=d*d;
}
int main()
{
int r,c,d;
cin>>r>>c>>d;
memset(head,-1,sizeof head);
tot=0;
for(int i=0;i<r;i++){
scanf("%s",s[i]);
for(int j=0;s[i][j];j++)
if(s[i][j]!='0')
dv.push_back(point(i,j,s[i][j]-'0'));
}
int cnt=0;
memset(vis,0,sizeof vis);
for(int i=0;i<r;i++){
scanf("%s",s[i]);
for(int j=0;s[i][j];j++)
if(s[i][j]=='L'){
vis[i][j]=1;
cnt++;
}
}
for(int i=0;i<dv.size();i++){
if(vis[dv[i].x][dv[i].y])
insert(0,i+1,1); //超级源
insert(i+1,i+501,dv[i].w); //柱子拆分
}
for(int i=0;i<dv.size();i++)
for(int j=0;j<dv.size();j++)
if(i!=j&&dis(i,j,d))
insert(i+501,j+1,inf); //柱子间
for(int i=0;i<dv.size();i++)
if(dv[i].x-d<0||dv[i].x+d>=r||dv[i].y-d<0||dv[i].y+d>=c)
insert(i+501,1000,inf); //能跳出边界的有高度的柱子
cout<<cnt-dinic()<<endl;
return 0;
}
同一道题:poj2711这次裸敲dinic,呵呵!
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 1567 | Accepted: 623 |
Description
Leave no lizard behind! Get as many lizards as possible out of the room, and report the number of casualties.
The pillars in the room are aligned as a grid, with each pillar one unit away from the pillars to its east, west, north and south. Pillars at the edge of the grid are one unit away from the edge of the room (safety). Not all pillars necessarily have a lizard. A lizard is able to leap onto any unoccupied pillar that is within d units of his current one. A lizard standing on a pillar within leaping distance of the edge of the room may always leap to safety... but there's a catch: each pillar becomes weakened after each jump, and will soon collapse and no longer be usable by other lizards. Leaping onto a pillar does not cause it to weaken or collapse; only leaping off of it causes it to weaken and eventually collapse. Only one lizard may be on a pillar at any given time.
Input
Each input map is guaranteed to be a rectangle of size n x m, where 1 <= n <= 20 and 1 <= m <= 20. The leaping distance is always 1 <= d <= 3.
Output
Sample Input
4 3 1 1111 1111 1111 LLLL LLLL LLLL 3 2 00000 01110 00000 ..... .LLL. ..... 3 1 00000 01110 00000 ..... .LLL. ..... 5 2 00000000 02000000 00321100 02000000 00000000 ........ ........ ..LLLL.. ........ ........
Sample Output
Case #1: 2 lizards were left behind. Case #2: no lizard was left behind. Case #3: 3 lizards were left behind. Case #4: 1 lizard was left behind.
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#define Maxn 1210
using namespace std;
const int inf=0x3f3f3f3f;
struct point{
int x,y,w;
point(int xx,int yy,int ww):x(xx),y(yy),w(ww){}
};
struct line{
int to,next,cap;
}p[640010];
int tot,src,t;
int head[Maxn],d[Maxn],q[Maxn];
char s[30][30];
int vis[30][30];
vector<point> dv;
void addedge(int a,int b,int c){
p[tot].to=b;
p[tot].next=head[a];
p[tot].cap=c;
head[a]=tot++;
}
void insert(int a,int b,int c){
addedge(a,b,c);
addedge(b,a,0);
}
bool bfs(){
memset(d,-1,sizeof d);
d[src]=0;
int s=0,e=-1;
q[++e]=src;
while(s<=e){
int u=q[s++];
for(int i=head[u];i!=-1;i=p[i].next){
int v=p[i].to;
if(d[v]==-1&&p[i].cap){
d[v]=d[u]+1;
q[++e]=v;
}
}
}
return d[t]!=-1;
}
int dfs(int u,int alpha){
if(u==t) return alpha;
int w,used=0;
for(int i=head[u];i!=-1&&used<alpha;i=p[i].next){
int v=p[i].to;
if(d[v]==d[u]+1&&p[i].cap){
w=dfs(v,min(alpha-used,p[i].cap));
used+=w;
p[i].cap-=w;
p[i^1].cap+=w;
}
}
if(!used) d[u]=-1;
return used;
}
int dinic(){
int ans=0;
src=0,t=1000;
while(bfs())
ans+=dfs(src,inf);
return ans;
}
bool dis(int i,int j,int d){
return (dv[i].x-dv[j].x)*(dv[i].x-dv[j].x)+
(dv[i].y-dv[j].y)*(dv[i].y-dv[j].y)<=d*d;
}
int main()
{
int test,r,c,d,cas=1;
cin>>test;
while(test--){
tot=0;
memset(head,-1,sizeof head);
printf("Case #%d: ",cas++);
cin>>r>>d;
c=0;
dv.clear();
for(int i=0;i<r;i++){
scanf("%s",s[i]);
for(int j=0;s[i][j];j++){
if(i==0) c++;
if(s[i][j]!='0')
dv.push_back(point(i,j,s[i][j]-'0'));
}
}
int cnt=0;
memset(vis,0,sizeof vis);
for(int i=0;i<r;i++){
scanf("%s",s[i]);
for(int j=0;s[i][j];j++)
if(s[i][j]=='L'){
vis[i][j]=1;
cnt++;
}
}
for(int i=0;i<dv.size();i++){
if(vis[dv[i].x][dv[i].y]) insert(0,i+1,1);
insert(i+1,i+501,dv[i].w);
}
for(int i=0;i<dv.size();i++)
for(int j=0;j<dv.size();j++)
if(i!=j&&dis(i,j,d)) insert(i+501,j+1,inf);
for(int i=0;i<dv.size();i++)
if(dv[i].x-d<0||dv[i].x+d>=r||dv[i].y-d<0||dv[i].y+d>=c)
insert(i+501,1000,inf);
int res=dinic();
if(res==cnt) printf("no lizard was left behind.\n");
else if(cnt-res==1) printf("%d lizard was left behind.\n",cnt-res);
else printf("%d lizards were left behind.\n",cnt-res);
}
return 0;
}