Matrix Again(最大费用最大流)

本文针对HDU问题2686 MatrixAgain,详细解析了如何利用最大费用最大流算法解决这一复杂数字游戏问题,包括从左上角到右下角再返回左上角的过程中,如何确保不重复经过同一区域(除起终点外),并给出具体实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Matrix Again

Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 102400/102400 K (Java/Others)
Total Submission(s): 16 Accepted Submission(s): 7
 
Problem Description
Starvae very like play a number game in the n*n Matrix. A positive integer number is put in each area of the Matrix.
Every time starvae should to do is that choose a detour which from the top left point to the bottom right point and than back to the top left point with the maximal values of sum integers that area of Matrix starvae choose. But from the top to the bottom can only choose right and down, from the bottom to the top can only choose left and up. And starvae can not pass the same area of the Matrix except the start and end..
Do you know why call this problem as “Matrix Again”? AS it is like the problem 2686 of HDU.
 
Input
The input contains multiple test cases.
Each case first line given the integer n (2<=n<=600) 
Then n lines, each line include n positive integers. (<100)
 
Output
For each test case output the maximal values starvae can get.
 
Sample Input
2
10 3
5 10
3
10 3 3
2 5 3
6 7 10
5
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
5 6 7 8 9
 
Sample Output
28
46
80
 
Author
Starvae
 
Source
HDOJ Monthly Contest – 2010.04.04
 
Recommend
lcy
 
/*
题意:给你一个n*n的矩阵每个点都有相应的权值,然后让你求出从左上角走到右下角,再返回能讲过的最大权值是多少,但是两次的路
    线不能经过同一个点。

#初步思路:最大费用最大流由于每个数只能取一次,所以对当前每一个数要进行拆点,将i拆为i和i'',然后从i连接一条边到i''
    ,容量为1,费用为第i个点的费用,然后将i和取完i点后能取的数连一条边,容量为1,费用为0。因为是从(1,1)->(n,n)->(1,
    1),所以我们建立超级源点S,连接S和第一个节点,容量为2(因为要走两条路径),费用为0,建立超级汇点T,连接点(n*n)'' 到
    T,容量为1,费用为0,然后求一次最大费用最大流,因为1和n*n这两个点算了两次,故需要减去一次他们的费用之和,发现网络流的题
    目数组的大小很重要,之前因为数组问题出现了各种错误,望今后引起高度重视


#补充:超内存......用数组来模拟栈就过了
*/

#include<bits/stdc++.h>
using namespace std;
int n;
int mapn[610][610];
int tol=0;
/**************************************************数组模拟************************************************************/
const int MAXN = 720010;
const int MAXM = 3501000;
const int INF = 1<<30;
struct EDG{
    int to,next,cap,flow;
    int cost;  //单价
}edg[MAXM];
int head[MAXN],eid;
int pre[MAXN], cost[MAXN] ; //点0~(n-1)

void init(){
    eid=0;
    memset(head,-1,sizeof(head));
}
void addEdg(int u,int v,int cap,int cst){
    edg[eid].to=v; edg[eid].next=head[u]; edg[eid].cost = cst;
    edg[eid].cap=cap; edg[eid].flow=0; head[u]=eid++;

    edg[eid].to=u; edg[eid].next=head[v]; edg[eid].cost = -cst;
    edg[eid].cap=0; edg[eid].flow=0; head[v]=eid++;
}

bool inq[MAXN];
int q[MAXN];
bool spfa(int sNode,int eNode , int n){
    int l=0,r=0;
    for(int i=0; i<n; i++){
        inq[i]=false; cost[i]= -1;
    }
    cost[sNode]=0; inq[sNode]=1; pre[sNode]=-1;
    q[r++]=sNode;
    while(l!=r){
        int u=q[l++]; //数组模拟
        if(l==MAXN)l=0;
        inq[u]=0;
        for(int i=head[u]; i!=-1; i=edg[i].next){
            int v=edg[i].to;
            if(edg[i].cap-edg[i].flow>0 && cost[v]<cost[u]+edg[i].cost){ //在满足可增流的情况下,最小花费
                cost[v] = cost[u]+edg[i].cost;
                pre[v]=i;   //记录路径上的边
                if(!inq[v]){
                    if(r==MAXN)r=0;
                    q[r++]=v; inq[v]=1;
                }
            }
        }
    }
    return cost[eNode]!=-1;    //判断有没有增广路
}
//反回的是最大流,最小花费为minCost
int minCost_maxFlow(int sNode,int eNode ,int& minCost , int n){
    int ans=0;
    while(spfa(sNode,eNode , n)){

        for(int i=pre[eNode]; i!=-1; i=pre[edg[i^1].to]){
            edg[i].flow+=1; edg[i^1].flow-=1;
            minCost+=edg[i].cost;
        }
        ans++;
        if(ans==2)break;
    }
    return ans;
}
/**************************************************数组模拟************************************************************/
int main(){
    // freopen("in.txt","r",stdin);
    while(scanf("%d",&n)!=EOF){
        //cout<<n<<endl;
        tol=n*n;//总的点数
        init();
        //  首先是初始化,总共可能n*n个点 0到n*n-1
        //  但是这个题还需要回来,所以可能走的点就是 
        //  2*n*n
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                scanf("%d",&mapn[i][j]);
            }
        }
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                if(i||j){ //如果这个点不是起点
                    
                    addEdg(i*n+j, i*n+j+n*n , 1 , mapn[i][j]);  
                    //如果这个点还没有到达右边的边界
                    if(j+1<n)//向右边走一步
                        addEdg(i*n+j+n*n, i*n+j+1 , 1 , 0 );

                    //如果这个点还没有到达下面的边界
                    if(i+1<n)//想下边走一步
                        addEdg(i*n+j+n*n, (i+1)*n+j , 1 , 0);  
                }  
                else{//如果这个点是原点的话
                    addEdg(0 , 1 , 1,0) , addEdg(0 , n , 1 , 0);  
                }  
            }
        }
        int ans=0;
        minCost_maxFlow(0,tol-1,ans,tol*2);
        ans+=mapn[0][0];
        if(n>1) ans+=(mapn[n-1][n-1]);
        printf("%d\n",ans);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/wuwangchuxin0924/p/6511632.html

最小费用最大流是一个经典的网络流问题,可以使用MATLAB来解决。MATLAB中有许多网络流算法的实现,其中包括最小费用最大流算法。以下是一个简单的MATLAB代码,可以用来解决最小费用最大流问题: ```matlab function [f, cost] = min_cost_max_flow(C, s, t, demand) % C: cost matrix, C(i,j) is the cost of sending one unit of flow from i to j % s: source node % t: sink node % demand: demand vector, demand(i) is the demand at node i % f: flow matrix, f(i,j) is the flow from i to j % cost: the minimum cost of sending the required demand n = size(C, 1); % number of nodes f = zeros(n); % initialize flow matrix while true % find shortest path from s to t using the Bellman-Ford algorithm [dist, prev] = bellman_ford(C, s); if dist(t) == inf % if there is no path from s to t, terminate break end % initialize residual capacity matrix res_cap = zeros(n); for i = 1:n for j = 1:n res_cap(i,j) = C(i,j) - f(i,j); end end % find the bottleneck capacity bottleneck = demand(t); node = t; while node ~= s bottleneck = min(bottleneck, res_cap(prev(node), node)); node = prev(node); end % update flow matrix and demand vector node = t; while node ~= s f(prev(node), node) = f(prev(node), node) + bottleneck; f(node, prev(node)) = f(node, prev(node)) - bottleneck; demand(node) = demand(node) - bottleneck; demand(prev(node)) = demand(prev(node)) + bottleneck; node = prev(node); end end % calculate minimum cost cost = 0; for i = 1:n for j = 1:n cost = cost + f(i,j) * C(i,j); end end end function [dist, prev] = bellman_ford(C, s) % C: cost matrix, C(i,j) is the cost of sending one unit of flow from i to j % s: source node % dist: distance vector, dist(i) is the shortest distance from s to i % prev: predecessor vector, prev(i) is the node that precedes i on the shortest path from s to i n = size(C, 1); % number of nodes dist = inf(1, n); % initialize distance vector prev = zeros(1, n); % initialize predecessor vector dist(s) = 0; % distance from source to source is zero for k = 1:n-1 % iterate n-1 times for i = 1:n for j = 1:n if C(i,j) ~= 0 && dist(i) + C(i,j) < dist(j) dist(j) = dist(i) + C(i,j); prev(j) = i; end end end end end ``` 这个代码实现了最小费用最大流算法,其中使用了Bellman-Ford算法来寻找最短路径。你可以根据自己的需求来调整代码,并在MATLAB中运行它。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值