网络流24题-20

来源:互联网 发布:精准医学大数据 编辑:程序博客网 时间:2024/05/22 02:29

深海机器人问题

«问题描述:
深海资源考察探险队的潜艇将到达深海的海底进行科学考察。潜艇内有多个深海机器
人。潜艇到达深海海底后,深海机器人将离开潜艇向预定目标移动。深海机器人在移动中还
必须沿途采集海底生物标本。沿途生物标本由最先遇到它的深海机器人完成采集。每条预定
路径上的生物标本的价值是已知的,而且生物标本只能被采集一次。本题限定深海机器人只
能从其出发位置沿着向北或向东的方向移动,而且多个深海机器人可以在同一时间占据同一
位置。
«编程任务:
用一个 P ́Q 网格表示深海机器人的可移动位置。西南角的坐标为(0,0)
,东北角的坐
标为 (Q,P)。
给定每个深海机器人的出发位置和目标位置,以及每条网格边上生物标本的价值。 计算
深海机器人的最优移动方案, 使深海机器人到达目的地后,采集到的生物标本的总价值最高。
«数据输入:
由文件 input.txt 提供输入数据。文件的第 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)位置坐标作为目的地。
«结果输出:程序运行结束时,将采集到的生物标本的最高总价值输出到文件 output.txt 中。
输入文件示例
input.txt 输出文件示例
output.txt
1 1
2 2
1 2
3 4
5 6
7 2
8 10
9 3
2 0 0
2 2 2 42

【问题分析】

最大费用最大流问题。

【建模方法】

把网格中每个位置抽象成网络中一个节点,建立附加源S汇T。

1、对于每个顶点i,j为i东边或南边相邻的一个节点,连接节点i与节点j一条容量为1,费用为该边价值的有向边。
2、对于每个顶点i,j为i东边或南边相邻的一个节点,连接节点i与节点j一条容量为无穷大,费用为0的有向边。
3、从S到每个出发点i连接一条容量为该点出发的机器人数量,费用为0的有向边。
4、从每个目标点i到T连接一条容量为可以到达该点的机器人数量,费用为0的有向边。

求最大费用最大流,最大费用流值就采集到的生物标本的最高总价值。

【建模分析】

这个问题可以看做是多出发点和目的地的网络运输问题。每条边的价值只能计算一次,容量限制要设为1。同时还将要连接上容量不限,费用为0的重边。由于“多个深海机器人可以在同一时间占据同一位置”,所以不需限制点的流量,直接求费用流即可。

#include<iostream>#include<math.h>#include<cstring>#include<algorithm>#include<set>#include<map>#include<queue>#include<cstdio>#include<vector>const int INF=0x7fffffff;const int maxn=1000;using namespace std;struct edge{    int to,cap,cost,rev;};vector<edge> G[maxn];int dist[maxn],prevv[maxn],preve[maxn];int V,S,T,P,Q,A,B,minflow=INF;void add_edge(int from,int to,int cap,int cost){    G[from].push_back((edge){to,cap,cost,G[to].size()});    G[to].push_back((edge){from,0,-cost,G[from].size()-1});    //cout<<from<<"to:"<<to<<" "<<cap<<" "<<cost<<endl;}int min_cost_flow(int s,int t,int f){    int res=0;    while(f>0)    {        fill(dist,dist+V+1,INF);        bool update=true;        dist[s]=0;        while(update)        {            update=false;            for(int v=0;v<=V;v++)            {                if(dist[v]==INF)                    continue;                for(int i=0;i<G[v].size();i++)                {                    edge &e=G[v][i];                    if(e.cap&&dist[e.to]>dist[v]+e.cost)                    {                        dist[e.to]=dist[v]+e.cost;                        prevv[e.to]=v;                        preve[e.to]=i;                        update=true;                    }                }            }        }        if(dist[t]==INF)            return -1;        int d=f;        for(int v=t;v!=s;v=prevv[v])            d=min(G[prevv[v]][preve[v]].cap,d);        f-=d;        res+=d*dist[t];        for(int v=t;v!=s;v=prevv[v])        {            edge &e=G[prevv[v]][preve[v]];            e.cap-=d;            G[e.to][e.rev].cap+=d;        }    }    return res;}inline int point1(int p,int q){    return (p-1)*(P+1)+(q);}inline int point2(int q,int p){    return (p-1)*(P+1)+(q);}void init(){    int tep;    cin>>A>>B;    cin>>P>>Q;    S=0;    T=(P+1)*(Q+1);    V=T;    for(int i=1;i<=P+1;i++)        for(int j=2;j<=Q+1;j++)    {        cin>>tep;        add_edge(point1(i,j-1),point1(i,j),1,-tep);    }    for(int i=1;i<=Q+1;i++)        for(int j=2;j<=P+1;j++)    {        cin>>tep;        add_edge(point2(i,j-1),point2(i,j),1,-tep);    }    for(int i=1;i<P+1;i++)        for(int j=1;j<Q+1;j++)        {            add_edge(point1(i,j),point1(i,j+1),INF,0);            add_edge(point1(i,j),point1(i+1,j),INF,0);        }    for(int i=1;i<=A;i++)    {        int k,x,y;        cin>>k>>x>>y;        minflow=min(minflow,k);        add_edge(S,point1(x+1,y+1),k,0);    }    for(int i=1;i<=B;i++)    {        int k,x,y;        cin>>k>>x>>y;        minflow=min(minflow,k);        add_edge(point1(x+1,y+1),T,k,0);    }}void solve(){    int ans=min_cost_flow(S,T,minflow);    cout<<-ans<<endl;}int main(){    init();    solve();    return 0;}