HDU 3376

http://acm.hdu.edu.cn/showproblem.php?pid=3376

题意:一个矩阵,每个点有价值,起点左上角终点右下角,每次只能走当前点的下一点或右一点,从起点走到终点,再从终点回到起点,走的点不能重复,问能取到的最大价值

用费用流做

建图:

拆点(保证每个点只取1次),除了起点和终点其他点拆点的容量是1,起点终点容量是2(走来回)

可以加源点汇点,最后答案刨去一次起点终点的价值(因为费用流会加两次),也可以不加,最后自己加上起点终点的价值

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std ;
const int INF=0xfffffff ;
struct node{
    int s,t,cap,cost,nxt ;
}e[4000005] ;
int sumflow ;
int n,m,cnt,head[1000005],vis[1000005],dis[1000005],pre[1000005] ;
void add(int s,int t,int cap,int cost)
{
    e[cnt].s=s ;e[cnt].t=t ;e[cnt].cap=cap ;e[cnt].cost=cost ;e[cnt].nxt=head[s] ;head[s]=cnt++ ;
    e[cnt].s=t ;e[cnt].t=s ;e[cnt].cap=0 ;e[cnt].cost=-cost ;e[cnt].nxt=head[t] ;head[t]=cnt++ ;
}
int spfa(int s,int t,int N)
{
    for(int i=0 ;i<=N ;i++)
        dis[i]=INF ;
    dis[s]=0 ;
    memset(vis,0,sizeof(vis)) ;
    memset(pre,-1,sizeof(pre)) ;
    vis[s]=1 ;
    queue <int> q ;
    q.push(s) ;
    while(!q.empty())
    {
        int u=q.front() ;
        q.pop() ;
        vis[u]=0 ;
        for(int i=head[u] ;i!=-1 ;i=e[i].nxt)
        {
            int tt=e[i].t ;
            if(e[i].cap && dis[tt]>dis[u]+e[i].cost)
            {
                dis[tt]=dis[u]+e[i].cost ;
                pre[tt]=i ;
                if(!vis[tt])
                {
                    vis[tt]=1 ;
                    q.push(tt) ;
                }
            }
        }
    }
    if(dis[t]==INF)return 0 ;
    return 1 ;
}
int MCMF(int s,int t,int N)
{
    int flow,minflow,mincost ;
    mincost=flow=0 ;
    while(spfa(s,t,N))
    {
        minflow=INF ;
        for(int i=pre[t] ;i!=-1 ;i=pre[e[i].s])
            minflow=min(minflow,e[i].cap) ;
        flow+=minflow ;
        for(int i=pre[t] ;i!=-1 ;i=pre[e[i].s])
        {
            e[i].cap-=minflow ;
            e[i^1].cap+=minflow ;
        }
        mincost+=dis[t]*minflow ;
    }
    sumflow=flow ;//最大流
    return mincost ;
}
int num[605][605],M[605][605] ;
int main()
{
    while(~scanf("%d",&n))
    {
        cnt=0 ;
        memset(head,-1,sizeof(head)) ;
        int S=0 ;
        int T=2*n*n+1 ;
        int ct=1 ;
        for(int i=1 ;i<=n ;i++)
            for(int j=1 ;j<=n ;j++)
            {
                scanf("%d",&M[i][j]) ;
                num[i][j]=ct++ ;
            }
           add(S,1,2,0) ;
           add(n*n*2,T,2,0) ;
          for(int i=1 ;i<=n ;i++)
          {
              for(int j=1 ;j<=n ;j++)
              {
                  if(num[i][j]==1)add(num[i][j],num[i][j]+n*n,2,-M[i][j]) ;
                  else if(num[i][j]==n*n)add(num[i][j],num[i][j]+n*n,2,-M[i][j]) ;
                  else add(num[i][j],num[i][j]+n*n,1,-M[i][j]) ;
                  if(i<n)add(num[i][j]+n*n,num[i][j]+n,1,0) ;
                  if(j<n)add(num[i][j]+n*n,num[i][j]+1,1,0) ;
              }
          }
          printf("%d\n",-(MCMF(S,T,T+1)+M[1][1]+M[n][n])) ;
    }
    return 0 ;
}

HDU 3376

时间: 2024-12-06 06:04:08

HDU 3376的相关文章

POJ 2135 Farm Tour &amp;&amp; HDU 2686 Matrix &amp;&amp; HDU 3376 Matrix Again 费用流求来回最短路

累了就要写题解,最近总是被虐到没脾气. 来回最短路问题貌似也可以用DP来搞,不过拿费用流还是很方便的. 可以转化成求满流为2 的最小花费.一般做法为拆点,对于 i 拆为2*i 和 2*i+1,然后连一条流量为1(花费根据题意来定) 的边来控制每个点只能通过一次. 额外添加source和sink来控制满流为2. 代码都雷同,以HDU3376为例. #include <algorithm> #include <iostream> #include <cstring> #in

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&

HDU 2686 &amp;&amp; HDU 3376(网络流之费用流)

题目地址:HDU 2686       HDU 3376 这两道题目除了数据大小外是一样的.前者只有30*30,但是后者却成了600*600..本来以为前者代码用到后者会超时,迟迟没敢交,但是感觉能用费用流的话也只能这么做了,于是改了改数组大小就交上去了.还真没超时.. 这题又是一道关于来回最短路的.最大费用可以把费用改成相反数,最后再转成相反数就是最大费用了. 建图思路是拆点,限制每个点只能经过一次.然后将每个点与右边的和下边的连边.源点与汇点要设为2个流量. 不知道为什么用G++叫就一直WA

HDU 3376 Matrix Again

Matrix Again Time Limit: 2000ms Memory Limit: 102400KB This problem will be judged on HDU. Original ID: 337664-bit integer IO format: %I64d      Java class name: Main Starvae very like play a number game in the n*n Matrix. A positive integer number i

hdu 3376 Matrix Again【最大费用流】

Matrix Again Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others) Total Submission(s): 2947    Accepted Submission(s): 860 Problem Description Starvae very like play a number game in the n*n Matrix. A positive integer

HDU 3376 Matrix Again(最大费用最大流)HDU2686加强题

Matrix Again Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others) Total Submission(s): 3206    Accepted Submission(s): 937 Problem Description Starvae very like play a number game in the n*n Matrix. A positive integer

HDU 3376 费用流 Matrix Again

咳咳,内个,内什么,白书上的费用流模板没过,后来换了种存图方式才过. 题意: 给出一个n × n的矩阵,每个格子中有一个数字代表权值,找出从左上角出发到右下角的两条不相交的路径(起点和终点除外),使得两条路径权值之和最大. 分析: 如果n比较小的话是可以DP的,但是现在n非常大,DP会超时的. 这个用费用流来求解: 因为每个点只能走一次,所以先拆点,两点之间连一条容量为1费用为对应格子权值的边,如果是起点或终点,因为要走两次,所以要连容量为2的边. 对于不同格子之间,如果能到达,连一条容量为IN

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

Soj题目分类

-----------------------------最优化问题------------------------------------- ----------------------常规动态规划  SOJ1162 I-Keyboard  SOJ1685 Chopsticks SOJ1679 Gangsters SOJ2096 Maximum Submatrix  SOJ2111 littleken bg SOJ2142 Cow Exhibition  SOJ2505 The County