HDU 3376 && 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>
#include <algorithm>
#include <stdlib.h>

#define N 605*605*2
#define M N*2
#define inf 1<<29
#define ll int

using namespace std;

//双向边,注意RE
//注意 点标必须是 [0 - 汇点]
struct Edge{
    ll from, to, flow, cap, nex, cost;
}edge[M*2];

ll head[N], edgenum;
void add(ll u,ll v,ll cap,ll cost){//网络流要加反向弧
    Edge E={u, v, 0, cap, head[u], cost};
    edge[edgenum]=E;
    head[u]=edgenum++;

    Edge E2={v, u, 0, 0, head[v], -cost}; //这里的cap若是单向边要为0
    edge[edgenum]=E2;
    head[v]=edgenum++;
}
ll D[N], P[N], A[N];
bool inq[N];
bool BellmanFord(ll s, ll t, ll &flow, ll &cost){
    for(ll i=0;i<=t;i++) D[i]= inf;

    memset(inq, 0, sizeof(inq));
    D[s]=0;  inq[s]=1; P[s]=0; A[s]=inf;

    queue<ll> Q;
    Q.push( s );
    while( !Q.empty()){
        ll u = Q.front(); Q.pop();
        inq[u]=0;
        for(ll i=head[u]; i!=-1; i=edge[i].nex){
            Edge &E = edge[i];
            if(E.cap > E.flow && D[E.to] > D[u] +E.cost){
                D[E.to] = D[u] + E.cost ;
                P[E.to] = i;
                A[E.to] = min(A[u], E.cap - E.flow);
                if(!inq[E.to]) Q.push(E.to) , inq[E.to] = 1;
            }
        }
    }
    if(D[t] == inf) return false;
    flow += A[t];
    cost += D[t] * A[t];
    ll u = t;
    while(u != s){
        edge[P[u]].flow += A[t];
        edge[P[u]^1].flow -= A[t];
        u = edge[P[u]].from;
    }
    return true;
}

ll Mincost(ll s,ll t){//返回最小费用
    ll flow = 0, cost = 0;
    while(BellmanFord(s, t, flow, cost));
    return cost;
}
void init(){memset(head,-1,sizeof head); edgenum = 0;}
ll n;
ll Hash(ll x,ll y){return (x-1)*n+y;}
ll Hash2(ll x,ll y){return n*n+(x-1)*n+y;}
ll mp[605][605];
int main(){
    ll i, j, u, v, cost;
    while(~scanf("%d",&n)){
        init();
        for(i=1;i<=n;i++)for(j=1;j<=n;j++)scanf("%d",&mp[i][j]);
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                add(Hash(i,j),Hash2(i,j),1,-mp[i][j]);
                u = Hash2(i,j);
                if(i!=n)
                {
                    v = Hash(i+1,j);
                    add(u,v,3,0);
                }
                if(j!=n)
                {
                    v = Hash(i,j+1);
                    add(u,v,3,0);
                }
            }
        }
		add(Hash(1,1), Hash2(1,1), 1, 0);
		add(Hash(n,n), Hash2(n,n), 1, 0);
        printf("%d\n",-Mincost(Hash(1,1), Hash2(n,n)));
    }
    return 0;
}
时间: 2024-11-05 12:19:04

HDU 3376 &amp;&amp; 2686 方格取数 最大和 费用流裸题的相关文章

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)->

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 预备知识: 对于一个无向

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

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

HDU 2167 状压dp方格取数

题意:给出一个数表,规定取出一个数后周围的八个数都不可取,求可获得的最大数字和 思路:状态压缩dp,每一行的取数方法为状态,显然,由于取数规则的限制,可取的状态并不是 1<<size_col,而是非常有限的,我们可以预处理出状态(不超过1600个),大大降低时间复杂度, 运行时间:140ms #include <bits/stdc++.h> using namespace std; int dp[16][1600],sta[1600],len,n; int g[15][15]; v

[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容

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

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

hdu 1565 方格取数(2)(网络流之最大点权独立集)

题目链接:hdu 1565 方格取数(2) 题意: 有一个n*m的方格,每个方格有一个数,现在让你选一些数.使得和最大. 选的数不能有相邻的. 题解: 我们知道对于普通二分图来说,最大独立点集 + 最小点覆盖集 = 总点数,类似的,对于有权的二分图来说,有: 最大点权独立集 + 最小点权覆盖集 = 总点权和, 这个题很明显是要求 最大点权独立集 ,现在 总点权 已知,我们只要求出来 最小点权覆盖集 就好了,我们可以这样建图, 1,对矩阵中的点进行黑白着色(相邻的点颜色不同),从源点向黑色的点连一

hdu 1569 方格取数(2) 网络流 最大点权独立集

方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5146    Accepted Submission(s): 1610 Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的