洛谷 1004 dp或最大费用流

思路:

dp方法:

    设dp[i][j][k][l]为两条没有交叉的路径分别走到(i,j)和(k,l)处最大价值。

    则转移方程为

    dp[i][j][k][l]=max(dp[i-1][j][k-1][l],dp[i][j-1][k-1][l],dp[i-1][j][k][l-1],dp[i][j-1][k][l-1])+map[i][j]+map[k][l];

    若两点相同减去一个map[i][j]即可

费用流方法(可以扩展为k条路径,但时间复杂度较高):

    源点连接左上角点流量为k、费用为0,右下角点连接汇点流量为k、费用为0,所有点连接右边相邻和下边相邻点流量为k、费用为0,所有点拆点一条流量为1、费用为该

    点价值,一条流量为k-1、费用为0。跑最大费用流即可

代码:

dp:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5 #include <vector>
 6 #include <queue>
 7 #include <cmath>
 8 #include <set>
 9 using namespace std;
10
11 #define N 55
12
13 __int64 map[N][N];
14 __int64 dp[N][N][N][N];
15 int n, m;
16
17 main()
18 {
19     int i, j, k, l;
20     int x, y, w;
21     while(scanf("%d %d",&n,&m)==2){
22         memset(map,0,sizeof(map));
23         memset(dp,0,sizeof(dp));
24         for(i=1;i<=n;i++){
25             for(j=1;j<=m;j++){
26                 scanf("%I64d",&map[i][j]);
27             }
28         }
29         for(i=1;i<=n;i++){
30             for(j=1;j<=m;j++){
31                 for(k=1;k<=n;k++){
32                     for(l=1;l<=m;l++){
33                         dp[i][j][k][l]=max(dp[i][j][k][l],dp[i-1][j][k-1][l]);
34                         dp[i][j][k][l]=max(dp[i][j][k][l],dp[i][j-1][k-1][l]);
35                         dp[i][j][k][l]=max(dp[i][j][k][l],dp[i-1][j][k][l-1]);
36                         dp[i][j][k][l]=max(dp[i][j][k][l],dp[i][j-1][k][l-1]);
37                         dp[i][j][k][l]+=map[i][j]+map[k][l];
38                         if(i==k&&j==l) dp[i][j][k][l]-=map[i][j];
39                     }
40                 }
41             }
42         }
43         printf("%I64d\n",dp[n][m][n][m]);
44     }
45 }

费用流:

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <iostream>
  5 #include <vector>
  6 #include <queue>
  7 #include <cmath>
  8 #include <set>
  9 using namespace std;
 10
 11 #define N 205
 12 #define M 1005
 13 #define inf 999999999
 14
 15 struct MCF{//min_cost_flow
 16     struct Edge{
 17         int v, f, w, next;
 18         Edge(){};
 19         Edge(int a,int b,int c,int d){
 20             v=a;f=b;w=c;next=d;
 21         }
 22     };
 23     int n;
 24     int head[N+10];
 25     Edge e[M*2];
 26     int nume;
 27     int src, sink;
 28
 29     void init(int st, int end,int nn){//初始化
 30         src=st;sink=end;n=nn;
 31         memset(head,0,sizeof(head));
 32         nume=1;
 33     }
 34
 35     void addedge(int u,int v,int c,int w){
 36         e[++nume]=Edge(v,c,w,head[u]);
 37         head[u]=nume;
 38         e[++nume]=Edge(u,0,-w,head[v]);
 39         head[v]=nume;
 40     }
 41
 42
 43     queue<int>Q;
 44     bool visited[N];
 45     int dis[N];
 46     int prev[N], pree[N];
 47
 48     bool findpath(){
 49
 50         while(!Q.empty()) Q.pop();
 51         Q.push(src);
 52         for(int i=0;i<=n;i++) dis[i]=-1;
 53         dis[src]=0;
 54         visited[src]=true;
 55         while(!Q.empty()){
 56             int u=Q.front();Q.pop();visited[u]=false;
 57             for(int i=head[u];i;i=e[i].next){
 58                 if(e[i].f>0&&dis[u]+e[i].w>dis[e[i].v]){
 59                     dis[e[i].v]=dis[u]+e[i].w;
 60                     prev[e[i].v]=u;
 61                     pree[e[i].v]=i;
 62                     if(!visited[e[i].v]){
 63                         Q.push(e[i].v);
 64                         visited[e[i].v]=true;
 65                     }
 66                 }
 67             }
 68         }//printf("111111\n");
 69         if(dis[sink]>0) return true;
 70         else return false;
 71     }
 72
 73     int solve(){
 74
 75         int u=sink;
 76         int flow=inf;
 77         while(u!=src){
 78             if(e[pree[u]].f<flow) flow=e[pree[u]].f;
 79             u=prev[u];
 80         }
 81         u=sink;
 82         while(u!=src){
 83             e[pree[u]].f-=flow;
 84             e[pree[u]^1].f+=flow;
 85             u=prev[u];
 86         }
 87
 88         return dis[sink]*flow;
 89     }
 90
 91     int mincostflow(){
 92         int ans=0;
 93         while(findpath()){
 94             ans+=solve();
 95         }
 96         return ans;
 97     }
 98 }mcf;
 99
100 int n;
101 int map[10][10];
102
103 int x, y, w;
104
105 main()
106 {
107     int i, j, k;
108     while(scanf("%d",&n)==1){
109         memset(map,0,sizeof(map));
110         while(1){
111
112             scanf("%d %d %d",&x,&y,&w);
113             if(x==0&&y==0&&w==0) break;
114             map[x][y]=w;
115         }
116         mcf.init(0,n*n*2+1,n*n*2+2);
117         mcf.addedge(0,1,2,0);
118         mcf.addedge(n*n*2,n*n*2+1,2,0);
119         int temp=1;
120         for(i=1;i<=n;i++){
121             for(j=1;j<=n;j++){
122                 mcf.addedge(temp,temp+n*n,1,map[i][j]);
123                 mcf.addedge(temp,temp+n*n,1,0);
124                 if(i<n) mcf.addedge(temp+n*n,temp+n,2,0);
125                 if(j<n) mcf.addedge(temp+n*n,temp+1,2,0);
126                 temp++;
127             }
128         }
129         printf("%d\n",mcf.mincostflow());
130     }
131 }  

时间: 2024-08-02 18:24:13

洛谷 1004 dp或最大费用流的相关文章

洛谷 P4014 分配问题 【最小费用最大流+最大费用最大流】

其实KM更快--但是这道题不卡,所以用了简单粗暴的费用流,建图非常简单,s向所有人连流量为1费用为0的边来限制流量,所有工作向t连流量为1费用为0的边,然后对应的人和工作连(i,j,1,cij),跑一遍最小费用最大流再跑一遍最大费用最大流即可.方便起见直接重建图了. #include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; const

洛谷 P4015 运输问题 【最小费用最大流+最大费用最大流】

s向仓库i连ins(s,i,a[i],0),商店向t连ins(i+m,t,b[i],0),商店和仓库之间连ins(i,j+m,inf,c[i][j]).建两次图分别跑最小费用最大流和最大费用最大流即可. #include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; const int N=1000005,inf=1e9; int n,m,h

【DP】洛谷1004方格取数

题目在这里 首先想到的是DFS,附上80分代码(不知道为什么WA了一个点): #include <cstdio> #include <cstring> #define N 1001 int max(int a,int b){return a > b ? a : b;} int n,ans[N][N],f[N][N],sum = 0; bool u[N][N]; void Del(int x,int y){ ans[x][y] = 0; if(x == 1 &&

洛谷1004方格取数

P1004 方格取数 题目描述 设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放 人数字0.如下图所示(见样例): A 0 0 0 0 0 0 0 0 0 0 13 0 0 6 0 0 0 0 0 0 7 0 0 0 0 0 0 14 0 0 0 0 0 21 0 0 0 4 0 0 0 0 15 0 0 0 0 0 0 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 . B 某人从图的左上角的A点出发,可以向下行走,也可以向右走,直到到达右下角

洛谷 P1433 DP 状态压缩

题目描述 房间里放着n块奶酪.一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在(0,0)点处. 输入输出格式 输入格式: 第一行一个数n (n<=15) 接下来每行2个实数,表示第i块奶酪的坐标. 两点之间的距离公式=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)) 输出格式: 一个数,表示要跑的最少距离,保留2位小数. 输入输出样例 输入样例#1: 4 1 1 1 -1 -1 1 -1 -1 输出样例#1: 7.41 这题开始用搜索做的,稍微剪下枝就能水过去

洛谷 P3254 圆桌问题【最大流】

s向所有单位连流量为人数的边,所有饭桌向t连流量为饭桌容量的边,每个单位向每个饭桌连容量为1的边表示这个饭桌只能坐这个单位的一个人.跑dinic如果小于总人数则无解,否则对于每个单位for与它相连.满流.另一端不是s的点则是最终方案 #include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; const int N=1000005,inf

AC日记——导弹拦截 洛谷 P1020 (dp+模拟)

题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹. 输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统. 输入输出格式 输入格式: 一行,若干个正整数最多100个. 输

洛谷P4003 无限之环(infinityloop)(网络流,费用流)

洛谷题目传送门 题目 题目描述 曾经有一款流行的游戏,叫做 Infinity Loop,先来简单的介绍一下这个游戏: 游戏在一个 n ? m 的网格状棋盘上进行,其中有些小方格中会有水管,水管可能在格子某些方向的边界的中点有接口,所有水管的粗细都相同,所以如果两个相邻方格的共边界的中点都有接头,那么可以看作这两个接头互相连接.水管有以下 15 种形状: 游戏开始时,棋盘中水管可能存在漏水的地方. 形式化地:如果存在某个接头,没有和其它接头相连接,那么它就是一个漏水的地方. 玩家可以进行一种操作:

洛谷 P4012 深海机器人问题【费用流】

题目链接:https://www.luogu.org/problemnew/show/P4012 洛谷 P4012 深海机器人问题 输入输出样例 输入样例#1: 1 1 2 2 1 2 3 4 5 6 7 2 8 10 9 3 2 0 0 2 2 2 输出样例#1: 42 说明 题解:建图方法如下: 对于矩阵中的每个点,向东.向北分别与其相邻点都要连两条边(重边): 1)容量为1,费用为该边价值的边: 2)容量为INF,费用为0的边(因为多个深海机器人可以在同一时间占据同一位置). 对于每个起点