【最大流 && 点限流】HDU

来源:互联网 发布:合肥数码美工招聘信息 编辑:程序博客网 时间:2024/06/05 11:11

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 0x3f3f3f3fnode 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);    }}
原创粉丝点击