【最大流 && 点限流】HDU - 2732 Leapin' Lizards

Problem Description

输入T代表有T组测试数据,输入n, d。代表接下来的有两个矩阵n行len列(列是不知道的)。第一个矩阵每个点代表着柱子,对应的值,代表这个柱子的承受能力,青蛙从这里跳走承受能力就会–,直至0就不能承受青蛙了。第二个矩阵L代表青蛙一开始在这里,.代表没有青蛙。问你最少还有多少只青蛙不能跳出边界。每次青蛙能跳的最大距离为d。

思路

核心是能想到最大流,紧接着是建图。拆点限流流量为承受能力,因为点点之间可以到达,所以建图需要注意指向。注意输出样例。was were

#include<bits/stdc++.h>
using namespace std;
struct node
{
    int to, cap, next;
};
#define inf 0x3f3f3f3f
node Map[1000000];
int head[1000], vis[1000], cnt;
char s[50][50];
void add(int u, int v, int w)//前向星存图
{
    Map[cnt].to = v;
    Map[cnt].cap = w;
    Map[cnt].next = head[u];
    head[u] = cnt++;
    Map[cnt].to = u;
    Map[cnt].cap = 0;
    Map[cnt].next = head[v];
    head[v] = cnt++;
}
bool bfs(int s, int e)
{
    memset(vis, -1, sizeof(vis));
    queue<int> q;
    q.push(s);
    vis[s] = 0;
    while(!q.empty())
    {
        s = q.front(), q.pop();
        for(int i = head[s]; ~i; i = Map[i].next)
        {
            int to = Map[i].to, cap = Map[i].cap;
            if(vis[to] == -1 && cap)
            {
                vis[to] = vis[s] + 1;
                q.push(to);
            }
        }
    }
    if(vis[e] == -1) return 0;
    else return 1;
}
int dfs(int s, int e, int f)
{
    if(s == e) return f;
    int ans = 0;
    for(int i = head[s]; ~i; i = Map[i].next)
    {
        int to = Map[i].to, &cap = Map[i].cap;
        if(vis[to] > vis[s] && cap)
        {
            int d = dfs(to, e, min(f, cap));
            if(d)
            {
                cap -= d;
                Map[i^1].cap += d;
                f -= d;
                ans += d;
                if(!f) break;
            }
        }
    }
    if(ans) return ans;
    vis[s] = -1;
    return 0;
}
int dinic(int s, int e)//求最大流
{
    int ans = 0;
    while(bfs(s, e))
    {
        ans += dfs(s, e, inf);
    }
    return ans;
}
double dist(node x, node y)//两点之间的距离
{
    return sqrt(double((x.to - y.to)*(x.to - y.to) + (x.cap - y.cap)*(x.cap - y.cap)));
}
int main()
{
    int T, Case = 1, n, m, d, i, j, len;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d %d", &n, &d);
        memset(head, -1, sizeof(head));
        cnt = 0;
        vector<node> p, ins;
        for(i = 0; i < n; i++)
        {
            scanf("%s", s[i]);
            len = strlen(s[i]);
            for(j = 0; j < len; j++)
            {
                if(s[i][j] != '0')
                    p.push_back((node){i, j, s[i][j] - '0'});//存起来所有能承受青蛙的柱子
            }
        }
        for(i = 0; i < n; i++)
        {
            scanf("%s", s[i]);
            for(j = 0; j < len; j++)
            {
                if(s[i][j] == 'L')
                ins.push_back((node){i, j});//存起来所有一开始青蛙的位置
            }
        }
        int cn = n;
        n = p.size();
        for(i = 0; i < n; i++)
        {
            add(i+1, i+n+1, p[i].next);//拆点限流
            if((d - p[i].to >= 1) || (d - p[i].cap >= 1) || (len - p[i].cap <= d) || (cn - p[i].to <= d))//能直接跳出去的柱子
            {
                add(i+n+1, 2*n+1, inf);
            }
            for(j = i+1; j < n; j++)
            {
                double dis = dist(p[i], p[j]);
                if(dis > d) continue;
                add(i+n+1, j+1, inf);//点点之间能够到达的建边 并且双向
                add(j+n+1, i+1, inf);
            }
        }
        m = ins.size();
        for(i = 0; i < m; i++)
        {
            for(j = 0; j < n; j++)
            {
                if(p[j].to == ins[i].to && p[j].cap == ins[i].cap)//一开始 有青蛙的点
                    add(0, j+1, 1);
            }
        }
        int ans = dinic(0, 2*n+1);//求最大流,最后注意输出格式
        if(ans == m) printf("Case #%d: no lizard was left behind.\n", Case++);
        else if(ans == m - 1) printf("Case #%d: 1 lizard was left behind.\n", Case++);
        else
        printf("Case #%d: %d lizards were left behind.\n", Case++, m - ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值