HDU-2732 Leapin' Lizards(网络流)

HDU-2732 Leapin’ Lizards(网络流)

Your platoon of wandering lizards has entered a strange room in the labyrinth you are exploring. As you are looking around for hidden treasures, one of the rookies steps on an innocent-looking stone and the room’s floor suddenly disappears! Each lizard in your platoon is left standing on a fragile-looking pillar, and a fire begins to rage below… 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
The input file will begin with a line containing a single integer representing the number of test cases, which is at most 25. Each test case will begin with a line containing a single positive integer n representing the number of rows in the map, followed by a single non-negative integer d representing the maximum leaping distance for the lizards. Two maps will follow, each as a map of characters with one row per line. The first map will contain a digit (0-3) in each position representing the number of jumps the pillar in that position will sustain before collapsing (0 means there is no pillar there). The second map will follow, with an ‘L’ for every position where a lizard is on the pillar and a ‘.’ for every empty pillar. There will never be a lizard on a position where there is no pillar.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
For each input case, print a single line containing the number of lizards that could not escape. The format should follow the samples provided below.
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.

题目大意:

有一些虫子,在一些柱子上,洪水来了,虫子要跳出矩阵才算获救,每个柱子都有一个最多承受跳跃次数。
给你n,k.n是柱子的行数。注意是行数不是列数,k是虫子能跳跃的距离(哈密顿距离
然后给你一个n行m列的矩阵,这个m没有给出,表示每个柱子最多能承受多少次虫子跳跃。
再给你一个n*m矩阵,L表示这个位置有虫子。
问:最后剩下多少只虫子没有获救。

解题思路:

一眼就能看出用网络流,但是如何建图呢?
首先每个柱子,也就是这个点有一个权值,所以我们想到把这个点拆成两个点x. x’ 连边权值就表示能经受的次数。
每个虫子我们看作一个点,连向这个虫子所在的柱子。流量是1.
每个虫子连超级源点,流量是1.
每个柱子拆分成了两个点,然后看从这个柱子能跳到哪个柱子上,这两个柱子之间连双向边,假设这两个点u,v,拆分后为u u’ v v’ 连边的时候,u’连v v’连u. 流量为inf。然后看这个柱子能不能直接跳出去,如果能就把这个点连向汇点。流量为inf。
这样建好图后就可以跑网络流了。
(这个图不是很好画,因为柱子之间相互连,在这就不画图了)

注意点:

  • 输出要注意是was 还是 were ?lizard还是lizards?
  • 数组要开大!虽然题目n只有20,但是如果你开小了它就会T。我也不知道为何。
  • 建图的时候一定注意别建错,那么些点,很容易写错。写错一个图就错了。我就因为建图的时候错了一个点wa了好多次。。。。
  • 注意它能跳的是哈密顿距离,而不是直线距离。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <algorithm>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn =1e4+10;
int n,m,sp,tp;
int jump;
int head[maxn*2],cnt = 0;
int deep[maxn*2];
int len ;
int cur[maxn];
struct node{
    int to;
    int w;
    int next;
}side[maxn*4];
void init(){
    memset(head,-1,sizeof(head));
    cnt = 0;
}
void add(int x,int y,int w){
    side[cnt].to = y;
    side[cnt].w = w;
    side[cnt].next = head[x];
    head[x] = cnt++;
}
bool bfs(){
    memset(deep,-1,sizeof(deep));
    queue<int> q;
    q.push(sp);
    deep[sp] = 0;
    while(q.size()){
        int now = q.front();
        q.pop();
        for(int i=head[now];i!=-1;i=side[i].next){
            int to = side[i].to;
            if(deep[to]==-1&&side[i].w>0){
                deep[to] = deep[now]+1;
                q.push(to);
                if(to == tp) break;
            }
        }
    }
    return deep[tp]!=-1;
}
int dfs(int u,int cap){
    if(u==tp||cap==0) return cap;
    int res = 0;
    int f;
    for(int &i=cur[u];i!=-1;i=side[i].next){
        int to = side[i].to;
        if(deep[to]==deep[u]+1&&(f=dfs(to,min(side[i].w,cap-res)))>0){
            side[i].w-=f;
            side[i^1].w+=f;
            res+=f;
            if(res==cap) return cap;
        }
    }
    if(!res) deep[u] = -1;
    return res;
}
int Dinic(){
    int ans = 0;
    while(bfs()){
        for(int i = 0;i<=tp;i++) cur[i] = head[i];
        ans +=dfs(sp,inf);
    }
    return ans ;    
}
struct Node{
    int x;
    int y;
    int bear;//能承担几次跳跃
}column[maxn],worm[maxn];
char mp[maxn];
bool can(int x,int y){
    if(x-0<=jump) return true;
    if(y-0<=jump) return true;
    if(len+1-y<=jump) return true;
    if(n+1-x<=jump) return true;
    return false;
}
int main(){
    int t;
    cin>>t;
    int cas = 1;
    while(t--){
        scanf("%d%d",&n,&jump);
        init();
        int cnt1 = 0;//柱子 
        int cnt2 = 0;//虫子 
        int tmp;
        for(int i=1;i<=n;i++){
            scanf("%s",mp+1);
            len = strlen(mp+1);
            for(int j=1;j<=len;j++){
                tmp = mp[j]-'0';
                if(tmp == 0) continue;
                cnt1++;
                column[cnt1].x = i;
                column[cnt1].y = j;
                column[cnt1].bear = tmp;
            }
        }

        for(int i=1;i<=n;i++){
            scanf("%s",mp+1);
            len = strlen(mp+1);
            for(int j=1;j<=len;j++){
                char ch = mp[j];
                if(ch == 'L'){
                    cnt2++;
                    worm[cnt2].x = i;
                    worm[cnt2].y = j;
                }
            }
        }

        sp = 1;
        tp = 2+cnt2+cnt1*2;        
        for(int i=1;i<=cnt2;i++){///虫子 
            add(1,i+1,1);
            add(i+1,1,0);
            for(int j=1;j<=cnt1;j++){//柱子 
                if(worm[i].x == column[j].x&&worm[i].y == column[j].y){
                    add(i+1,j+cnt2+1,1);
                    add(j+cnt2+1,i+1,0);
                    break;
                   // printf("add %d %d\n",i+1,j+cnt2+1);
                } 
            }
        }
        for(int i=1;i<=cnt1;i++){//柱子之间 
            add(i+cnt2+1,i+cnt2+cnt1+1,column[i].bear);
            add(i+cnt2+cnt1+1,i+cnt2+1,0);
            if(can(column[i].x,column[i].y)){//能跳出边界
                add(i+cnt1+cnt2+1,tp,inf);
                add(tp,i+cnt1+cnt2+1,0);
              //  printf("add %d   %d  --tp\n",i,i+cnt1+cnt2+1);
            }
            for(int j=i+1;j<=cnt1;j++){
                int dx= abs(column[i].x-column[j].x);
				int dy=abs(column[i].y-column[j].y);
				int dis = dx+dy;
                if(dis>jump) continue;
				else{
                    add(i+cnt2+cnt1+1,j+cnt2+1,inf);
                    add(j+cnt2+1,i+cnt2+cnt1+1,0);
                    add(j+cnt2+cnt1+1,i+cnt2+1,inf);
                    add(i+cnt2+1,j+cnt2+cnt1+1,0);
    
                }           
            }
        }
        int ans = Dinic();
        ans = cnt2 - ans;
        printf("Case #%d: ",cas++);
        if(ans==0){
            printf("no lizard was left behind.\n");
        }else if(ans == 1){
            printf("%d lizard was left behind.\n",ans);
        }else{
            printf("%d lizards were left behind.\n",ans);
        }
    }
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值