NEU 1458 方格取数(网络流之费用流)

题目地址:NEU 1458

跟杭电上的那两个方格取数不太一样。。这个可以重复,但是取和的时候只能加一次。建图思路基本一会就出来。同样的拆点,只不过这题需要再拆个边,其中一条费用0,另一条费用为那个点处的值。流量都限制为1.然后剩下的都跟杭电上的那两个差不多了。因为把数组开小了WA了好几发。。(我前面居然还专门检查了一下数组大小,居然当时还认为没开小。。。对自己无语。。)

代码如下:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <queue>
#include <map>
#include<algorithm>

using namespace std;
const int INF=0x3f3f3f3f;
int head[21000], source, sink, cnt, mp[101][101], flow, cost, n;
int vis[21000], d[21000], cur[21000];
struct node
{
    int u, v, cap, cost, next;
} edge[1000000];
void add(int u, int v, int cap, int cost)
{
    edge[cnt].v=v;
    edge[cnt].cap=cap;
    edge[cnt].cost=cost;
    edge[cnt].next=head[u];
    head[u]=cnt++;

    edge[cnt].v=u;
    edge[cnt].cap=0;
    edge[cnt].cost=-cost;
    edge[cnt].next=head[v];
    head[v]=cnt++;
}
int spfa()
{
    int i, minflow=INF;
    memset(d,INF,sizeof(d));
    memset(vis,0,sizeof(vis));
    cur[source]=-1;
    d[source]=0;
    queue<int>q;
    q.push(source);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(i=head[u]; i!=-1; i=edge[i].next)
        {
            int v=edge[i].v;
            if(d[v]>d[u]+edge[i].cost&&edge[i].cap)
            {
                d[v]=d[u]+edge[i].cost;
                minflow=min(minflow,edge[i].cap);
                cur[v]=i;
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    if(d[sink]==INF) return 0;
    flow+=minflow;
    cost-=minflow*d[sink];
    //printf("%d %d\n",minflow,d[sink]);
    for(i=cur[sink]; i!=-1; i=cur[edge[i^1].v])
    {
        edge[i].cap-=minflow;
        edge[i^1].cap+=minflow;
    }
    return 1;
}
void mcmf()
{
    flow=cost=0;
    while(spfa()) ;
    printf("%d\n",cost);
}
int main()
{
    int i, j;
    while(scanf("%d",&n)!=EOF)
    {
        for(i=1; i<=n; i++)
        {
            for(j=1; j<=n; j++)
            {
                scanf("%d",&mp[i][j]);
            }
        }
        memset(head,-1,sizeof(head));
        cnt=0;
        source=0;
        sink=2*n*n+1;
        add(source,1,2,0);
        add(2*n*n,sink,2,0);
        for(i=1; i<=n; i++)
        {
            for(j=1; j<=n; j++)
            {
                add((i-1)*n+j,(i-1)*n+j+n*n,1,0);
                add((i-1)*n+j,(i-1)*n+j+n*n,1,-mp[i][j]);
                if(1+j<=n)
                {
                    add((i-1)*n+j+n*n,(i-1)*n+j+1,2,0);
                }
                if(i+1<=n)
                {
                    add((i-1)*n+j+n*n,i*n+j,2,0);
                }
            }
        }
        mcmf();
    }
    return 0;
}

NEU 1458 方格取数(网络流之费用流),布布扣,bubuko.com

时间: 2024-10-07 06:44:45

NEU 1458 方格取数(网络流之费用流)的相关文章

HDU 3376 &amp;&amp; 2686 方格取数 最大和 费用流裸题

题意: 1.一个人从[1,1] ->[n,n] ->[1,1] 2.只能走最短路 3.走过的点不能再走 问最大和. 对每个点拆点限流为1即可满足3. 费用流流量为2满足1 最大费用流,先给图取负,结果再取负,满足2 #include <stdio.h> #include <string.h> #include <iostream> #include <math.h> #include <queue> #include <set&

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

题意:给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000) 现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0, 这样一共走K次,现在要求K次所达到的方格的数的和最大. n<=50,k<=10 思路:费用流 将每个点裂成一个出点和一个入点(i,j,1..2),这个思路与最大流类似 (i,j,1)->(i,j,2) 连两条边: 容量为1,费用为a[i,j] 容量为K,费用为0 (i,j,2)->

HDU 3376 &amp;amp;&amp;amp; 2686 方格取数 最大和 费用流裸题

题意: 1.一个人从[1,1] ->[n,n] ->[1,1] 2.仅仅能走最短路 3.走过的点不能再走 问最大和. 对每一个点拆点限流为1就可以满足3. 费用流流量为2满足1 最大费用流,先给图取负,结果再取负,满足2 #include <stdio.h> #include <string.h> #include <iostream> #include <math.h> #include <queue> #include <s

hdu1565方格取数(1)【最大流||最大点权独立集】

Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大. Input 包括多个测试实例,每个测试实例包括一个整数n 和n*n个非负数(n<=20) Output 对于每个测试实例,输出可能取得的最大的和 Sample Input 3 75 15 21 75 15 28 34 70 5 Sample Output 188 预备知识: 对于一个无向

BZOJ 1475: 方格取数( 网络流 )

本来想写道水题....结果调了这么久!就是一个 define 里面少加了个括号 ! 二分图最大点权独立集...黑白染色一下 , 然后建图 : S -> black_node , white_node -> T , 流量都为点权 . 然后 black_node -> white_node ( 两点有公共边 ) , 流量为 +oo , 然后 answer = ∑ w( i ) ( i ∈ V ) - maxflow --------------------------------------

P2774 方格取数问题 网络最大流 割

P2774 方格取数问题:https://www.luogu.org/problemnew/show/P2774 题意: 给定一个矩阵,取出不相邻的数字,使得数字的和最大. 思路: 可以把方格分成两个部分,横坐标和纵坐标和为奇数的一组,和为偶数的一组,超级源点向偶数一组连容量为格点数字大小的边,奇数一组向超级汇点连容量为格点大小的边.然后两组间相临的点连容量为无穷的边. 跑出这个图的最大流,相当于是最小割,就是去掉了最少的部分使得网络不流通.因此答案就是sum - dinic(): #inclu

[CodeVs1227]方格取数2(最大费用最大流)

网络流24题的坑还没填完就来搞其他题,你真的要TJ? 写这题给自己的费用流攒个模板. 题目大意:一个n*n的矩阵,每格有点权,从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走K次,现在要求K次所达到的方格的数的和最大. 啊简单的费用流.每个点i拆成i和i',连一条容量为1的边价值为点权,再连一条容量inf的边价值为0来让这个点能被经过,然后S连(1,1)容量k价值0,i'和右.下的点连容量inf价值0的边,(n,n)'连T容

方格取数(网络流24题)

题意 在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.对于给定的方格棋盘,按照取数要求编程找出总和最大的数. 题解 方格是常见的二分图(疑问脸).所以考虑先染色,相邻的格子颜色不同,这样就分成了二分图,先假设全选,然后跑最小割就好了,割掉就是不选. #include<bits/stdc++.h> using namespace std; const int maxn=10005;

【wikioi】1907 方格取数3(最大流+最大权闭合子图)

这题我一开始想到的是状压,看到n<=30果断放弃. 然后也想到了黑白染色,然后脑残了,没想到怎么连边. 很简单的一题 黑白染色后,每个点向四周连边,容量为oo,然后如果是黑(白)节点,源连一条边,容量为权值:如果是白(黑)节点,连一条边到汇,容量为权值. 最后答案为所有格子权值和-最大流(其实是最小割) ps:(其实就是之前做过的qq农场 囧..http://www.cnblogs.com/iwtwiioi/p/3893519.html 为什么这样做参考我以前写的博文(http://www.cn