题目描述
深海资源考察探险队的潜艇将到达深海的海底进行科学考察。
潜艇内有多个深海机器人。潜艇到达深海海底后,深海机器人将离开潜艇向预定目标移动。
深海机器人在移动中还必须沿途采集海底生物标本。沿途生物标本由最先遇到它的深海机器人完成采集。
每条预定路径上的生物标本的价值是已知的,而且生物标本只能被采集一次。
本题限定深海机器人只能从其出发位置沿着向北或向东的方向移动,而且多个深海机器人可以在同一时间占据同一位置。
用一个 p×q 网格表示深海机器人的可移动位置。西南角的坐标为 (0,0),东北角的坐标为 (p,q)。
给定每个深海机器人的出发位置和目标位置,以及每条网格边上生物标本的价值。
计算深海机器人的最优移动方案, 使深海机器人到达目的地后,采集到的生物标本的总价值最高。
输入格式
文件的第 1 行为深海机器人的出发位置数 a,和目的地数 b 。
第 2 行为 p 和 q 的值。
接下来的 p+1 行,每行有 q 个正整数,表示向东移动路径上生物标本的价值,行数据依从南到北方向排列。
再接下来的 q+1 行,每行有 p 个正整数,表示向北移动路径上生物标本的价值,行数据依从西到东方向排列。
接下来的 a 行,每行有 3 个正整数 k,x,y 表示有 k 个深海机器人从 (x,y) 位置坐标出发。
再接下来的 b 行,每行有 3 个正整数 r,x,y ,表示有 r 个深海机器人可选择 (x,y) 位置坐标作为目的地。
a 行和 b 行输入时横纵坐标要反过来。
输出格式
输出采集到的生物标本的最高总价值。
输入输出样例
输入 #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⩽p,q⩽15,1⩽a⩽4,1⩽b⩽6。
分析
给出了每条边的价值,要使多条路线的价值和最大,显然可以套用最大费用最大流模型。
不妨将 p,q 都加一,坐标原点设为 (1,1),方便表示坐标为 (x,y) 的点的编号。定义坐标为 (x,y) 的点的编号为 ID(x,y)=p(x−1)+y。
设源点 s,汇点 t。从 s 向每个机器人开始的地方连容量为机器人数量,费用为 0 的边。从每个目的地向 t连容量为 r,费用为 0 的边。这就限定了最大流为机器人的总数。
值得思考的是相邻点之间的连边。对于一个点 (x,y),其相邻点为 (x+1,y) 和 (x,y+1)。由于生物标本只能采集一次,可以从 (x,y) 向其相邻点连边,容量为 1,费用为采集生物标本的价值;但是同一位置可以容纳多个机器人停留,那么不妨再建一条容量为 +∞,费用为 0 的边。求最大费用最大流时,产生价值的边一定会满流,且流量只能为 1,另一条费用为 0 的边用来承载不采集标本的机器人。
最后求出的最大费用最大流即为答案。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
|
#include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int inf=0x3f3f3f3f; const int N=1003; struct E { int to; int cap; int cost; int Next; }; E edge[N<<6]; int head[N],tot; int incf[N],pre[N]; int dis[N]; bool inqueue[N]; int a,b; int p,q; int s,t; void init(); int ID(int,int); inline void add_edge(int,int,int,int); bool SPFA(); int MCMF(); int main() { int i,j; cin>>a>>b; cin>>p>>q; p++; q++; init(); for(j=1;j<=p;j++) { for(i=1;i<=q-1;i++) { int x; scanf("%d",&x); add_edge(ID(i,j),ID(i+1,j),1,-x); add_edge(ID(i,j),ID(i+1,j),inf,0); } } for(i=1;i<=q;i++) { for(j=1;j<=p-1;j++) { int x; scanf("%d",&x); add_edge(ID(i,j),ID(i,j+1),1,-x); add_edge(ID(i,j),ID(i,j+1),inf,0); } } while(a--) { int k,x,y; scanf("%d%d%d",&k,&y,&x); x++; y++; add_edge(s,ID(x,y),k,0); } while(b--) { int r,x,y; scanf("%d%d%d",&r,&y,&x); x++; y++; add_edge(ID(x,y),t,r,0); } cout<<-MCMF()<<endl; return 0; } void init() { tot=1; memset(head,-1,sizeof(head)); s=0; t=p*q+1; } inline void add_edge(int u,int v,int cap,int cost) { tot++; edge[tot].to=v; edge[tot].cap=cap; edge[tot].cost=cost; edge[tot].Next=head[u]; head[u]=tot; tot++; edge[tot].to=u; edge[tot].cap=0; edge[tot].cost=-cost; edge[tot].Next=head[v]; head[v]=tot; } bool SPFA() { queue<int>q; memset(dis,inf,sizeof(dis)); memset(inqueue,0,sizeof(inqueue)); q.push(s); dis[s]=0; inqueue[s]=1; incf[s]=inf; while(!q.empty()) { int x=q.front(); q.pop(); inqueue[x]=0; for(register int i=head[x];~i;i=edge[i].Next) { if(!edge[i].cap) continue; int y=edge[i].to; if(dis[y]>dis[x]+edge[i].cost) { dis[y]=dis[x]+edge[i].cost; incf[y]=min(incf[x],edge[i].cap); pre[y]=i; if(!inqueue[y]) { inqueue[y]=1; q.push(y); } } } } if(dis[t]==inf) return 0; else return 1; } int MCMF() { int maxflow,mincost; maxflow=mincost=0; while(SPFA()) { int x=t; while(x!=s) { int y=pre[x]; edge[y].cap-=incf[t]; edge[y^1].cap+=incf[t]; x=edge[y^1].to; } maxflow+=incf[t]; mincost+=dis[t]*incf[t]; } return mincost; } int ID(int x,int y) {return (x-1)*p+y;}
|