HDOJ 2686 - Matrix & HDOJ 3376 - Matrix Again 构图最小费用最大流 or dp

                    题意:

                             给一个矩阵..问从左上角走到右下角..再从右下角走回左上角..不经过重复的点并且从左上至至右下时只能向右或者向下走,从右下至左上时只能向上或者左走..经过一个点..加上它的值...问能取到的最大值是多少...

                    题解:

                             这题和曾经一道Noip的差不多...可以用三维的DP...也可以用最小费用最大流...为了限制点经过次数..必须拆点..注意的是起点和终点会经过两次..所以拆点后这两个点间的容量为2....


Program:

#include<iostream>  
#include<algorithm>  
#include<stdio.h>  
#include<string.h>  
#include<math.h>  
#include<queue>  
#define MAXN 5005  
#define MAXM 500005  
#define oo 1000000007  
#define ll long long  
using namespace std;    
struct MCMF    
{    
       struct node    
       {    
              int x,y,c,v,next;     
       }line[MAXM];    
       int Lnum,_next[MAXN],pre[MAXN],dis[MAXN],flow,cost;    
       bool inqueue[MAXN];    
       void initial(int n)    
       {    
              Lnum=-1;    
              for (int i=0;i<=n;i++) _next[i]=-1;    
       }    
       void addline(int x,int y,int c,int v)    
       {    
              line[++Lnum].next=_next[x],_next[x]=Lnum;    
              line[Lnum].x=x,line[Lnum].y=y,line[Lnum].c=c,line[Lnum].v=v;    
              line[++Lnum].next=_next[y],_next[y]=Lnum;    
              line[Lnum].x=y,line[Lnum].y=x,line[Lnum].c=0,line[Lnum].v=-v;    
       }    
       bool SPFA(int s,int e)    
       {    
              int x,k,y;    
              queue<int> Q;    
              while (!Q.empty()) Q.pop();    
              memset(dis,0x7f,sizeof(dis));    
              memset(inqueue,false,sizeof(inqueue));    
              Q.push(s);    
              dis[s]=0,pre[s]=-1;    
              while (!Q.empty())    
              {    
                      x=Q.front(),Q.pop(),inqueue[x]=false;    
                      for (k=_next[x];k!=-1;k=line[k].next)      
                         if (line[k].c)    
                         {    
                               y=line[k].y;    
                               if (dis[y]>dis[x]+line[k].v)    
                               {    
                                        dis[y]=dis[x]+line[k].v;    
                                        pre[y]=k;    
                                        if (!inqueue[y])    
                                        {    
                                                inqueue[y]=true;    
                                                Q.push(y);    
                                        }    
                               }    
                         }    
              }    
              if (dis[e]>oo) return false;    
              flow=oo,cost=0;    
              for (k=pre[e];k!=-1;k=pre[line[k].x])     
                  flow=min(flow,line[k].c),cost+=line[k].v;        
              cost*=flow;    
              for (k=pre[e];k!=-1;k=pre[line[k].x])    
                  line[k].c-=flow,line[k^1].c+=flow;      
              return true;    
       }    
       void MinCostMaxFlow(int s,int e,int &Aflow,int &Acost)    
       {    
              Aflow=0,Acost=0;    
              while (SPFA(s,e))    
              {    
                     Aflow+=flow;    
                     Acost+=cost;     
              }         
       }    
}T;     
int A[35][35];
int main() 
{              
      int n,i,j,x,h,hh,s,e,Ac;  
      while (~scanf("%d",&n))
      {
              s=0,e=n*n-1,T.initial(e<<2);
              for (i=0;i<n;i++)
                for (j=0;j<n;j++)
                {
                       scanf("%d",&x),h=i*n+j;
                       T.addline(h<<1,h<<1|1,1,-x);
                       if (i!=n-1) hh=h+n,T.addline(h<<1|1,hh<<1,1,0);
                       if (j!=n-1) hh=h+1,T.addline(h<<1|1,hh<<1,1,0);
                }
              T.addline(s<<1,s<<1|1,1,0),T.addline(e<<1,e<<1|1,1,0);
              s=s<<1,e=e<<1|1;
              T.MinCostMaxFlow(s,e,x,Ac);
              printf("%d\n",-Ac);
      }
      return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值