HDU 2686

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

and

http://codevs.cn/problem/1169/

题意: 从矩阵左上角1,1,走到右下角n,n,每次只能向右或向下走,到达nn后,再走回1,1,往回走时,每次只能向左或者向上走,除了11和nn,其他点在去和回的路径中只能出现一次,问权值和最大的来回的路径是多少。

解法:找一条来回的路径,相当于从11到nn找两条点不重复的路径,使得两条的和最大。 相当于从源点 给11一个2的流量, nn给汇点一个n的流量, 跑最大流, 两个流经过的两条路就是要找的答案。 为了保证一个点只会被选择一次,考虑拆点。

把矩阵中的点xy,拆成两个点,一个称为in,一个称为out,所有指向这个点的边 连到in,所有从xy出发的边,从out点连出去, in-》out连流量为1,费用为- a【x】【y】,求最小费用最大流, 相反数就是最大权值和。其他的边就是往右和往下建边。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int inf=0x3f3f3f3f;
  4 const int M=1e2+10;
  5 class MaxFlowMinCost { ///最小费用最大流O(~=V^3)
  6     typedef int typef;///流量的类型
  7     typedef int typec;///费用的类型
  8     static const int ME=1e6+10;///边的个数
  9     static const int MV=5e3+10;///点的个数
 10     queue<int> q;
 11     int n,cur[MV],pre[MV];
 12     bool used[MV],sign[MV];
 13     typef flow;
 14     typec cost,dist[MV];
 15     bool spfa(int s,int t) {
 16         for(int i=0; i<=n; i++) {
 17             used[i]=sign[i]=dist[i]=0;
 18         }
 19         used[s]=sign[s]=true;
 20         while(!q.empty()) q.pop();
 21         q.push(s);
 22         while(!q.empty()) {
 23 //            - 24 -
 24             int u=q.front();
 25             q.pop();
 26             used[u]=false;
 27             for(int i=g.head[u]; ~i; i=g.e[i].next) {
 28                 if(g.e[i].flow<1) continue;
 29                 int v=g.e[i].v;
 30                 typec c=g.e[i].cost;
 31                 if(!sign[v]||dist[v]>dist[u]+c) {
 32                     dist[v]=dist[u]+c;
 33                     sign[v]=true;
 34                     pre[v]=u;
 35                     cur[v]=i;
 36                     if(used[v]) continue;
 37                     used[v]=true;
 38                     q.push(v);
 39                 }
 40             }
 41         }
 42         return sign[t];
 43     }
 44     struct G {
 45         struct E {
 46             int v,next;
 47             typef flow;
 48             typec cost;
 49         } e[ME];
 50         int le,head[MV];
 51         void init(int n) {
 52             le=0;
 53             for(int i=0; i<=n; i++) head[i]=-1;
 54         }
 55         void add(int u,int v,typef flow,typec cost) {
 56             e[le].v=v;
 57             e[le].flow=flow;
 58             e[le].cost=cost;
 59             e[le].next=head[u];
 60             head[u]=le++;
 61         }
 62     } g;
 63 public:
 64     void init(int tn) {
 65         n=tn;
 66         g.init(n);
 67     }
 68 //    - 25 -
 69     void add(int u,int v,typef flow,typec cost) {
 70         g.add(u,v,flow,cost);
 71         g.add(v,u,0,-cost);
 72     }
 73     void solve(int s,int t) {
 74         flow=cost=0;
 75         while(spfa(s,t)) {
 76             int temp=t;
 77             typef now=inf;
 78             while(temp!=s) {
 79                 now=min(now,g.e[cur[temp]].flow);
 80                 temp=pre[temp];
 81             }
 82             flow+=now;
 83             temp=t;
 84             while(temp!=s) {
 85                 int id=cur[temp];
 86                 cost+=now*g.e[id].cost;
 87                 g.e[id].flow-=now;
 88                 g.e[id^1].flow+=now;
 89                 temp=pre[temp];
 90             }
 91         }
 92     }
 93     typef getflow() {
 94         return flow;
 95     }
 96     typec getcost() {
 97         return cost;
 98     }
 99 } gx;
100 int a[M][M];
101 int in[M][M];
102 int out[M][M];
103 int n,m;
104 int solve() {
105     int id=0;
106     for(int i=0; i<n; i++) {
107         for(int j=0; j<m; j++) {
108             in[i][j]=id;
109             id++;
110         }
111     }
112     for(int i=0; i<n; i++) {
113         for(int j=0; j<m; j++) {
114             out[i][j]=id;
115             id++;
116         }
117     }
118     int s=id;
119     id++;
120     int t=id;
121     id++;
122     gx.init(t);
123     gx.add(s,in[0][0],2,0);
124     gx.add(out[n-1][m-1],t,2,0);
125     for(int i=0; i<n; i++) {
126         for(int j=0; j<m; j++) {
127             int flow=1;
128             if(i==0&&j==0) flow=2;
129             if(i==n-1&&j==m-1) flow=2;
130             gx.add(in[i][j],out[i][j],flow,-a[i][j]);
131             if(i+1<n) {
132                 gx.add(out[i][j],in[i+1][j],1,0);
133             }
134             if(j+1<m) {
135                 gx.add(out[i][j],in[i][j+1],1,0);
136             }
137         }
138     }
139     gx.solve(s,t);
140     return -gx.getcost();
141 }
142 int main() {
143     while(~scanf("%d",&n)) {
144         m=n;
145         for(int i=0; i<n; i++) {
146             for(int j=0; j<m; j++) {
147                 scanf("%d",&a[i][j]);
148             }
149         }
150         printf("%d\n",solve()-a[0][0]-a[n-1][n-1]);
151     }
152     return 0;
153 }

有另一种动态规划解法,网上称之为多线程dp。

end

时间: 2024-07-31 11:21:54

HDU 2686的相关文章

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 2686 Matrix(最大费用最大流+拆点)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2686 和POJ3422一样 删掉K把汇点与源点的容量改为2(因为有两个方向的选择)即可 #include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> const int ma

POJ 3422 HDU 2686,3376 费用流拆点建图

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3376 http://acm.hdu.edu.cn/showproblem.php?pid=2686 http://poj.org/problem?id=3422 POJ 3422为从矩阵左上角走到右下角,最多走k次,每个格子里的数字只能算一次,后面可以重复经过,求经过的各个数字的和的最大值. 拆点,入点向出点连流量为1,费用为当前格子负值的边,向下方,右方连边,流量为k,费用为0,起点连流量为1,

HDU 2686 Matrix 3376 Matrix Again(费用流)

HDU 2686 Matrix 题目链接 3376 Matrix Again 题目链接 题意:这两题是一样的,只是数据范围不一样,都是一个矩阵,从左上角走到右下角在从右下角走到左上角能得到最大价值 思路:拆点,建图,然后跑费用流即可,不过HDU3376这题,极限情况是300W条边,然后卡时间过了2333 代码: #include <cstdio> #include <cstring> #include <vector> #include <queue> #i

hdu 2686 Matrix &amp;&amp; hdu 3367 Matrix Again (最大费用最大流)

Matrix Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1394    Accepted Submission(s): 758 Problem Description Yifenfei very like play a number game in the n*n Matrix. A positive integer number

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

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

hdu 2686 费用流 / 双线程DP

题意:给一个方阵,求从左上角出到右下角(并返回到起点),经过每个点一次不重复,求最大获益(走到某处获得改点数值),下来时每次只能向右或向下,反之向上或向左. 俩种解法: 1  费用流法:思路转化:从左上角流出2的流量,(表示走俩条路),归于右下角,可以走就有边(右和下),权为负的费用,源点连起点,汇点连终点,流量为2. 除源汇外所有点一分为2,Y向X对应点有流量1的边,之前边为X到Y的(原图),这样处理解决每个点只最多走一次(除了源汇外)(X部只出,Y部要出必先回到X对应点).跑最小费用最大流即

hdu 2686 Matrix 最小费用最大流

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2686 Yifenfei 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 yifenfei should to do is that choose a detour which frome the top left

HDU 2686 Matrix 多线程dp

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2686 思路:多线程dp,参考51Nod 1084:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1084 注:这道题用滚动数组优化反而WA,压到三维即可 代码: 1 #include <bits/stdc++.h> 2 using namespace std; 3 int ans[30][30],dp[60][30][3