hdu2732 网络流经典建图

http://acm.hdu.edu.cn/showproblem.php?pid=2732
题目大意:
给了n和d,表示有n行的图,(列数没给),对于每一个人都可以最长跳d的距离,对于每一个柱子有一个限定条件,只能从这里跳出去多少次。给了两张图,一张表示柱子的限定条件,一张给了现在那些柱子上有人。问有几个人不能跳到图的外面。
思路:
最大流建图。将图的外面抽象为一个汇点t,对于图中本来就可以跳出去的点,就可以连一条边到t了。对于可以跳到图中别的点的,就可以从这个点连一条边过去。比较直观的想法就是这些边的容量都设为这个柱子限定的次数,最后跑最大流就好了。但是如果这个柱子可以跳到旁边很多的点上,每一个边的容量都是这个限定次数的话,等于限定的次数被放大了。那么就考虑拆点,将每个点拆成点1,点2,1->2连一条边容量为限定的次数。对于能跳到别的边,就从2连一条边到外面的点,容量为INF。
步骤:
拆点
1.将能够直接跳出去的点,拆出的第一个点连到t,容量为限定的次数。
2.不能直接跳出去的,将点1连到点2,容量为限定的次数。
3.对于能跳到别的点的,将这个点2连到别的点的点1,容量为INF。
4.对于柱子上有人的,从s连一条边到该点的点1,容量为1。
跑最大流。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
using namespace std;
#define M 1009
typedef struct edge
{
    int to,cap,rev;
};
vector<edge> G[M];
char mp1[30][30],mp2[30][30];
int level[M],iter[M];
int n,m,d;
int T;
int s,t,sum;
const int INF = 0x3f3f3f3f;
void init()
{
    for(int i = 0;i <= 2*n*m+2;i++) G[i].clear();
    sum = 0;
}
int to1(int i,int j)
{
    return i*m + j+1;
}
int to2(int i,int j)
{
    return to1(i,j) + n*m;
}
int dis(int x1,int x2,int y1,int y2)
{
    return abs(x1-x2) + abs(y1-y2);
}
void add_edge(int u,int v,int cap)
{
    G[u].push_back(edge{v,cap,G[v].size()});
    G[v].push_back(edge{u,0,G[u].size()-1});
}
void bfs(int s)
{
    memset(level,-1,sizeof(level));
    level[s] = 0;
    queue<int> q;
    q.push(s);
    while(!q.empty())
    {
        int v = q.front();
        q.pop();
        for(int i = 0;i < G[v].size();i++)
        {
            edge& e = G[v][i];
            if(e.cap > 0 && level[e.to] < 0)
            {
                level[e.to] = level[v] + 1;
                q.push(e.to);
            }
        }
    }
}
int dfs(int u,int t,int f)
{
    if(u == t) return f;
    for(int& i = iter[u];i < G[u].size();i++)
    {
        edge& e = G[u][i];
        if(e.cap > 0 && level[e.to] > level[u])
        {
            int d = dfs(e.to,t,min(f,e.cap));
            if(d > 0)
            {
                e.cap -= d;
                G[e.to][e.rev].cap += d;
                return d;
            }
        }
    }
    return 0;
}
int max_flow()
{
    int flow = 0;
    for(;;)
    {
        bfs(s);
        memset(iter,0,sizeof(iter));
        if(level[t] < 0) return flow;
        int f = 0;
        while((f = dfs(s,t,INF)) > 0) flow += f;
    }
}
int main()
{
    scanf("%d",&T);
    int k = 0;
    while(k < T)
    {
        init();
        k++;
        scanf("%d %d",&n,&d);
        for(int i = 0;i < n;i++) scanf("%s",mp1[i]);
        m = strlen(mp1[0]);
        for(int i = 0;i < n;i++) scanf("%s",mp2[i]);
        s = 0;
        t = 2*n*m+1;
        for(int i = 0;i < n;i++)
        {
            for(int j = 0;j < m;j++)
            {
                if(mp1[i][j] - '0' > 0)
                {
                    //add_edge(to1(i,j),to2(i,j),mp1[i][j]-'0');
                    if(i+1 <= d || j+1 <= d || n-i <= d || m-j <= d)
                    {
                        add_edge(to1(i,j),t,mp1[i][j]-'0');
                        continue;
                    }
                    else add_edge(to1(i,j),to2(i,j),mp1[i][j]-'0');
                    for(int ii = -d;ii <= d;ii++)
                    {
                        for(int jj = -d;jj <= d;jj++)
                        {
                            int x = i + ii;
                            int y = j + jj;
                            if(x == i && y == j) continue;
                            if(x < 0 || y < 0 || x >= n || y >= m || dis(i,x,j,y) > d || mp1[x][y]-'0' == 0) continue;
                            add_edge(to2(i,j),to1(x,y),INF);
                        }
                    }
                }
            }
        }
        for(int i = 0;i < n;i++)
        {
            for(int j = 0;j < m;j++)
            {
                if(mp2[i][j] == 'L')
                {
                    add_edge(s,to1(i,j),1);
                    sum++;
                }
            }
        }
        int flow = max_flow();
        int ans = sum - flow;
        printf("Case #%d: ",k);
        if(ans > 1) printf("%d lizards were left behind.\n",ans);
        else if (ans == 1) printf("1 lizard was left behind.\n");
        else if (ans == 0) printf("no lizard was left behind.\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值