火星探险问题(最大费用最大流)

火星探险问题(luogu)

Solution

容易想到费用流

为解决点权问题,将一个不是障碍的点 i 拆成两个点 ai,bi

从 ai 向 bi 连一条流量为正无穷(表示可以无限次经过),费用为 0(表示这些经过没有收益)的边

若点 i 是石块,则再从 ai 向 bi 连一条流量为1(表示只能经过一次),费用为 1(表示这次经过收益为 1)的边

若点 i 可以到点 j 且 i 和 j 都不是障碍,则从 bi 向 aj 连一条流量为正无穷,费用为 0 的边

从起点向 a1 连一条流量为探测车数,费用为0的边

从 bn 向终点连一条流量为探测车数,费用为0的边

跑最大费用最大流

Code

#include <cstdio>
#include <cstdlib>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=3e3,M=1e5;
int pre[N],s,t,car,d[N],n,m,incf[N],a[40][40],inf=1<<30,dis[N];
int head[N],nxt[M],ver[M],edge[M],cost[M],tot=1,maxflow,maxcost;
bool in[N];
int id(int x,int y,int inv)
{
    return (x-1)*m+y+inv*n*m;
}
void add(int u,int v,int w,int c)
{
    ver[++tot]=v,nxt[tot]=head[u],edge[tot]=w,cost[tot]=c,head[u]=tot;
    ver[++tot]=u,nxt[tot]=head[v],edge[tot]=0,cost[tot]=-c,head[v]=tot;
}
bool spfa()
{
    memset(dis,0x80,sizeof(dis));
    memset(pre,0,sizeof(pre));
    int last=dis[s];
    queue <int> q;
    dis[s]=0,q.push(s),incf[s]=1<<30;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        in[u]=false;
        for(int i=head[u],v;i;i=nxt[i])
            if(edge[i]>0 && dis[v=ver[i]]<dis[u]+cost[i])
            {
                dis[v]=dis[u]+cost[i];
                incf[v]=min(edge[i],incf[u]);
                pre[v]=i;
                if(!in[v]) in[v]=true,q.push(v);
            }
    }
    return dis[t]!=last;
}
void update()
{
    maxflow+=incf[t],maxcost+=incf[t]*dis[t];
    int x=t;
    while(x!=s)
    {
        int i=pre[x];
        edge[i]-=incf[t],edge[i^1]+=incf[t];
        x=ver[i^1];
    }
}
void dfs(int x,int y,int pos,int k)
{
    int kx,ky,mov;
    for(int i=head[pos];i;i=nxt[i])
    {
        int v=ver[i];
        if(v==s || v==t || v==pos-n*m || edge[i^1]<=0) continue;
        edge[i^1]--;
        if(v>n*m)
        {
            dfs(x,y,v,k);
            return;
        }
        if(v==(x-1)*m+y+1) kx=x,ky=y+1,mov=1;
        else kx=x+1,ky=y,mov=0;
        printf("%d %d\n",k,mov);
        dfs(kx,ky,v+n*m,k);
        return;
    }
}
int main()
{
    scanf("%d%d%d",&car,&m,&n);
    s=0,t=n*m*2+1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&a[i][j]);
    if(a[n][m]==1 || a[1][1]==1) return 0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(a[i][j]==1) continue;
            add(id(i,j,0),id(i,j,1),inf,0);
            if(a[i][j]==2) add(id(i,j,0),id(i,j,1),1,1);
            if(i<n && a[i+1][j]!=1) add(id(i,j,1),id(i+1,j,0),inf,0);
            if(j<m && a[i][j+1]!=1) add(id(i,j,1),id(i,j+1,0),inf,0);
        }
    add(s,id(1,1,0),car,0),add(id(n,m,1),t,car,0);
    while(spfa()) update();
    for(int i=1;i<=maxflow;i++)
        dfs(1,1,1,i);
    return 0;
}

原文地址:https://www.cnblogs.com/hsez-cyx/p/12407511.html

时间: 2024-10-05 09:28:13

火星探险问题(最大费用最大流)的相关文章

【Luogu】P3356火星探险问题(费用流)

题目链接 网络流一条边都不能多连?没道理呀? 不过单看这题的确是个sb题…… #include<cstdio> #include<algorithm> #include<cstring> #include<cctype> #include<cstdlib> #include<queue> #define maxn 100 #define maxm 100000 #define lim n*m #define F(i,j) ((i-1)

火星探险问题 网络流

题目描述 火星探险队的登陆舱将在火星表面着陆,登陆舱内有多部障碍物探测车.登陆舱着陆后,探测车将离开登陆舱向先期到达的传送器方向移动.探测车在移动中还必须采集岩石标本.每一块岩石标本由最先遇到它的探测车完成采集.每块岩石标本只能被采集一次.岩石标本被采集后,其他探测车可以从原来岩石标本所在处通过.探测车不能通过有障碍的地面.本题限定探测车只能从登陆处沿着向南或向东的方向朝传送器移动,而且多个探测车可以在同一时间占据同一位置.如果某个探测车在到达传送器以前不能继续前进,则该车所采集的岩石标本将全部

【BZOJ3876】【Ahoi2014】支线剧情 有下界的最小费用最大流

#include <stdio.h> int main() { puts("转载请注明出处谢谢"); puts("http://blog.csdn.net/vmurder/article/details/43025375"); } [BZOJ2324]营救皮卡丘 这道题也是一道有下界的最小费用最大流. 我的题解地址:http://blog.csdn.net/vmurder/article/details/41378979 这道题其实就是模板题. 我的处理

POJ 3686.The Windy&#39;s 最小费用最大流

The Windy's Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 5477   Accepted: 2285 Description The Windy's is a world famous toy factory that owns M top-class workshop to make toys. This year the manager receives N orders for toys. The ma

P3381 【模板】最小费用最大流

P3381 [模板]最小费用最大流 题目描述 如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行包含四个正整数ui.vi.wi.fi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi),单位流量的费用为fi. 输出格式: 一行,包含两个整数,依次为最大流量和在最大流量情况下的

C++之路进阶——最小费用最大流(支线剧情)

F.A.Qs Home Discuss ProblemSet Status Ranklist Contest ModifyUser  hyxzc Logout 捐赠本站 Notice:由于本OJ建立在Linux平台下,而许多题的数据在Windows下制作,请注意输入.输出语句及数据类型及范围,避免无谓的RE出现. 3876: [Ahoi2014]支线剧情 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 542  Solved: 332[Submit

hdu 4494 Teamwork 最小费用最大流

Teamwork Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4494 Description Some locations in city A has been destroyed in the fierce battle. So the government decides to send some workers to repair these location

POJ - 2195 Going Home(最小费用最大流)

1.N*M的矩阵中,有k个人和k个房子,每个人分别进入一个房子中,求所有人移动的最小距离. 2.人看成源点,房子看成汇点,求最小费用最大流. 建图-- 人指向房子,容量为1,费用为人到房子的曼哈顿距离. 建立超级源点和超级汇点:超级源点指向人,容量为1,费用为0:超级汇点指向房子,容量为1,费用为0. 求超级源点到超级汇点的最小费用最大流即可. ps:容量为什么都设为1?---有待研究.. 3. 1.Bellman-Ford: #include<iostream> #include<st

hdu 1853 Cyclic Tour 最小费用最大流

题意:一个有向图,现在问将图中的每一个点都划分到一个环中的最少代价(边权和). 思路:拆点,建二分图,跑最小费用最大流即可.若最大流为n,则说明是最大匹配为n,所有点都参与,每个点的入度和出度又是1,所以就是环. /********************************************************* file name: hdu1853.cpp author : kereo create time: 2015年02月16日 星期一 17时38分51秒 *******