【codevs1227】方格取数2 费用流(EK)

题目描述 Description

给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走K次,现在要求K次所达到的方格的数的和最大

输入描述 Input Description

第一行两个数n,k(1<=n<=50, 0<=k<=10)

接下来n行,每行n个数,分别表示矩阵的每个格子的数

输出描述 Output Description

一个数,为最大和

样例输入 Sample Input

3 1

1 2 3

0 2 1

1 4 2

样例输出 Sample Output

11

数据范围及提示 Data Size & Hint

1<=n<=50, 0<=k<=10


把每个节点拆成两个,分别为ai和bi

ai向bi连边,费用为权值,容量为1
再连边,费用为0,容量为k,保证联通

其他能到达i号点的点,向ai连边,费用为0,流量为k。向外连边则用bi向外连。

新建节点s向< 1,1 >连边,费用为0,流量为k。
新建节点e向< n,n >连边,费用为0,流量为k。

然后s向e做最大费用流。

然后我想问,为什么我的dinic比EK慢!!dinic会T两个点!!

代码(EK):

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;

const int SZ=100010;
const int INF=1000000000;

int head[SZ],nxt[SZ],tot=1;

struct edge{
    int f,t,d,c;
}l[SZ];

void build(int f,int t,int d,int c)
{
    l[++tot].t=t;
    l[tot].f=f;
    l[tot].d=d;
    l[tot].c=c;
    nxt[tot]=head[f];
    head[f]=tot;
}

int s,e,n;

queue<int> q;

int pre[SZ],f[SZ],dist[SZ];
bool use[SZ];

bool spfa(int &cost,int &flow)
{
    for(int i=1;i<=n;i++) dist[i]=-INF;
    f[s]=INF;
    dist[s]=0;
    q.push(s);
    use[s]=1;
    while(q.size())
    {
        int f=q.front(); q.pop();
        use[f]=0;
        for(int i=head[f];i;i=nxt[i])
        {
            int v=l[i].t;
            if(l[i].c && dist[v] < dist[f] + l[i].d)
            {
                dist[v] = dist[f] + l[i].d;
                ::f[v] = min(::f[f],l[i].c);
                pre[v] = i;

                if(!use[v])
                {
                    use[v]=1;
                    q.push(v);
                }
            }
        }
    }
    if(dist[e]==-INF) return false;

    flow += f[e];
    cost += dist[e] * f[e];

    for(int i=e;i!=s;i=l[pre[i]].f)
    {
        l[pre[i]].c -= f[e];
        l[pre[i]^1].c += f[e];
    }
    return true;
}

int getnode(int x,int y)
{
    return (x-1)*n+y;
}

int EK()
{
    int cost=0,flow=0;
    while(spfa(cost,flow));
    return cost;
}


int main()
{
    int m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            int x;
            scanf("%d",&x);

            int sa = getnode(i,j),sb = getnode(i,j)+n*n;
            build(sa,sb,x,1);   build(sb,sa,-x,0);
            build(sa,sb,0,m);   build(sb,sa,0,0);

            if(i != n)
            {
                int ea = getnode(i+1,j);
                build(sb,ea,0,m); build(ea,sb,0,0);
            }
            if(j != n)
            {
                int ea = getnode(i,j+1); 
                build(sb,ea,0,m); build(ea,sb,0,0);
            }
        }
    }   
    s = n*n*2+1; e = n*n*2+2;
    build(s,1,0,m); build(1,s,0,0);
    build(n*n*2,e,0,m); build(e,n*n*2,0,0);
    n = n*n*2+2;
    printf("%lld",EK());

    return 0;
}

dinic:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

typedef long long LL;

const int SZ=1000010;
const int INF=1000000000;

int head[SZ],nxt[SZ],tot=1,n,m;

struct edge{
    int t,c;
    LL d;
}l[SZ];

void build(int f,int t,LL d,int c)
{
    l[++tot].t=t;
    l[tot].d=d;
    l[tot].c=c;
    nxt[tot]=head[f];
    head[f]=tot;
}

queue<int> q;

bool use[SZ];

int dist[SZ],s,e;

bool spfa()
{
    for(int i = 1;i <= n;i ++) dist[i] = -INF;
    dist[s] = 0;
    use[s] = 1;
    q.push(s);
    while(q.size())
    {
        int f=q.front(); q.pop();
        use[f] = 0;
        for(int i = head[f];i;i = nxt[i])
        {
            int v = l[i].t;
            if(l[i].c && dist[v] < dist[f] + l[i].d)
            {
                dist[v] = dist[f] + l[i].d;
                if(!use[v])
                {
                    use[v] = 1;
                    q.push(v);
                }
            }
        }
    }
    if(dist[e] == -INF) return false;
    return true;
}

bool vis[SZ];

int dfs(int u,int flow,LL &cost)
{
    if(u == e || flow == 0) return flow;
    int ans = 0;
    for(int i = head[u];i;i = nxt[i])
    if(!vis[i])
    {
        int v = l[i].t;
        if(l[i].c && dist[v] == dist[u] + l[i].d)
        {
            vis[i] = 1;
            int f = dfs(v,min(flow - ans,l[i].c),cost);
            if(f > 0)
            {
                cost += l[i].d * l[i].c;
                l[i].c -= f;
                l[i^1].c += f;
                ans += f;
                if(flow == ans) break;
            }
            vis[i] = 0;
        }
    }
    if(ans == 0) dist[u] = INF;
    return ans;
}


LL dinic()
{
    LL cost = 0;
    while(spfa())
    {
        int tmp = dfs(s,INF,cost);
        if(tmp == 0) break;
        memset(vis,0,sizeof(vis));
    }
    return cost;
}

int getnode(int x,int y)
{
    return (x-1)*n+y;
}


int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            int x;
            scanf("%d",&x);

            int sa = getnode(i,j),sb = getnode(i,j)+n*n;
            build(sa,sb,x,1);   build(sb,sa,-x,0);
            build(sa,sb,0,m);   build(sb,sa,0,0);

            if(i != n)
            {
                int ea = getnode(i+1,j);
                build(sb,ea,0,m); build(ea,sb,0,0);
            }
            if(j != n)
            {
                int ea = getnode(i,j+1); 
                build(sb,ea,0,m); build(ea,sb,0,0);
            }
        }
    }   
    s = n*n*2+1; e = n*n*2+2;
    build(s,1,0,m); build(1,s,0,0);
    build(n*n*2,e,0,m); build(e,n*n*2,0,0);
    n = n*n*2+2;
    printf("%lld",dinic());

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
方格数问题也可以使用网络算法进行求解。以下是一个Python实现: ```python from collections import deque n = int(input()) grid = [] for i in range(n): row = list(map(int, input().split())) grid.append(row) # 计算每个格子的编号 id_map = [[0] * n for _ in range(n)] cnt = 0 for i in range(n): for j in range(n): id_map[i][j] = cnt cnt += 1 # 定义网络图的源点、汇点,以及每个格子的容量 s = 2*n*n t = 2*n*n + 1 cap = [[0] * (2*n*n+2) for _ in range(2*n*n+2)] for i in range(n): for j in range(n): cap[s][id_map[i][j]] = 1 # 源点到每个格子的容量为1 cap[id_map[i][j]+n*n][t] = 1 # 每个格子到汇点的容量为1 if i > 0: # 上方格子向当前格子的容量为上方格子的值 cap[id_map[i-1][j]][id_map[i][j]+n*n] = grid[i][j] if j > 0: # 左方格子向当前格子的容量为左方格子的值 cap[id_map[i][j-1]][id_map[i][j]+n*n] = grid[i][j] # 使用BFS算法找到增广路径 def bfs(): queue = deque([s]) visited = [False] * (2*n*n+2) visited[s] = True parent = [-1] * (2*n*n+2) while queue: u = queue.popleft() for v in range(2*n*n+2): if not visited[v] and cap[u][v] > 0: visited[v] = True parent[v] = u queue.append(v) if v == t: # 找到增广路径 path = [] while v != s: path.append(v) v = parent[v] path.append(s) path.reverse() return path return None # 使用Ford-Fulkerson算法求最大 max_flow = 0 while True: path = bfs() if not path: break flow = float('inf') for i in range(len(path)-1): u, v = path[i], path[i+1] flow = min(flow, cap[u][v]) for i in range(len(path)-1): u, v = path[i], path[i+1] cap[u][v] -= flow cap[v][u] += flow max_flow += flow print(max_flow) ``` 这个算法将每个格子看做一个节点,将源点和汇点分别连接到每个格子。根据题目要求,每个格子只能向下或向右走,因此可以将每个格子拆成两个节点,一个表示向下走,一个表示向右走。这样就可以将问题转化为一个网络问题。 具体来说,源点向每个格子的向下走节点连边,容量为1;每个格子的向右走节点向汇点连边,容量为1;每个格子的向下走节点向下方格子的向上走节点连边,容量为下方格子的值;每个格子的向右走节点向左方格子的向右走节点连边,容量为左方格子的值。 然后使用标准的Ford-Fulkerson算法求解最大,即可得到答案。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值