【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)*m+j)
#define T(i,j) (F(i,j)+lim)
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch==‘-‘)    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-‘0‘;
        ch=getchar();
    }
    return num*f;
}

struct Edge{
    int from,next,to,val,dis,flow;
}edge[maxm];
int head[maxn*maxn],num;
inline void addedge(int from,int to,int val,int dis){
    edge[++num]=(Edge){from,head[from],to,val,dis,0};
    head[from]=num;
}
inline void add(int from,int to,int val,int dis){
    addedge(from,to,val,dis);
    addedge(to,from,0,-dis);
}

inline int count(int i){    return i&1?i+1:i-1;    }

int dis[maxn*maxn];
int flow[maxn*maxn];
int pre[maxn*maxn];
bool vis[maxn*maxn];
int Start,End;
int n,m;

int spfa(){
    memset(dis,-127/3,sizeof(dis));    dis[Start]=0;    flow[Start]=0x7fffffff;
    queue<int>q;    q.push(Start);
    while(!q.empty()){
        int from=q.front();    q.pop();    vis[from]=0;
        for(int i=head[from];i;i=edge[i].next){
            int to=edge[i].to;
            if(edge[i].val<=edge[i].flow||dis[to]>=dis[from]+edge[i].dis)    continue;
            dis[to]=dis[from]+edge[i].dis;
            pre[to]=i;    flow[to]=min(flow[from],edge[i].val-edge[i].flow);
            if(vis[to])    continue;
            vis[to]=1;    q.push(to);
        }
    }
    int now=End;
    while(now!=Start){
        int ret=pre[now];
        edge[ret].flow+=flow[End];
        edge[count(ret)].flow-=flow[End];
        now=edge[ret].from;
    }
    return dis[End];
}

struct Node{
    int x,y;
};

Node calc(int ret){
    Node ans;
    ans.x=(ret-1)/m+1;
    ans.y=ret-(ans.x-1)*m;
    return ans;
}

Node q[maxn*maxn];int tot;

void dfs(int x,int y,int now){
    if(now==End)    return;
    for(int i=head[now];i;i=edge[i].next){
        int to=edge[i].to;
        if(edge[i].flow==0)    continue;
        edge[i].flow--;    edge[i].val--;
        if(to<=lim)    q[++tot]=calc(to);
        dfs(q[tot].x,q[tot].y,to);
        return;
    }
}

bool ext[maxn][maxn];

int main(){
    int e=read();
    m=read();n=read();
    Start=1;    End=n*m*2;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j){
            int x=read();
            if(i!=1&&ext[i-1][j]==0)    add(T(i-1,j),F(i,j),0x7fffffff,0);
            if(j!=1&&ext[i][j-1]==0)    add(T(i,j-1),F(i,j),0x7fffffff,0);
            if(x==1){
                ext[i][j]=1;
                continue;
            }
            add(F(i,j),T(i,j),1,x==2?1:0);
            add(F(i,j),T(i,j),0x7fffffff,0);

        }
    int cnt=0;
    while(1){
        int now=spfa();
        if(now<0)    break;
        cnt++;
        if(cnt>e)    break;
        tot=0;
        dfs(1,1,1);
        q[0]=(Node){1,1};
        for(int j=1;j<=tot;++j){
            Node a=q[j-1],b=q[j];
            if(a.x==b.x)    printf("%d %d\n",cnt,1);
            else            printf("%d %d\n",cnt,0);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/cellular-automaton/p/8449320.html

时间: 2024-10-09 11:52:35

【Luogu】P3356火星探险问题(费用流)的相关文章

Luogu P4068 [SDOI2016]数字配对(费用流)

Luogu P4068 [SDOI2016]数字配对(费用流) 根据质因子个数奇偶性划分肯定会形成一张二分图. 把所有的\(a\)分解质因数,记录其质因子个数. \(a_i \% a_j == 0\)且\(a_i\)的质因子比\(a_j\)质因子个数多1的时候,我们连边. 解决这个题目的关键是求出费用\(>0\)的时候的最大的流量. 我们要跑最大费用最大流,(具体实现是把边权取反) 这样在每一次的增广过程中,我们都可以保证费用最大且满足流最多. 但是写法有异议,待填坑. 原文地址:https:/

luogu P2604 [ZJOI2010]网络扩容 |费用流

题目描述 给定一张有向图,每条边都有一个容量\(C\)和一个扩容费用\(W\).这里扩容费用是指将容量扩大1所需的费用.求: 1. 在不扩容的情况下,1到N的最大流: 2. 将1到N的最大流增加K所需的最小扩容费用. 输入格式 输入文件的第一行包含三个整数\(N,M,K\),表示有向图的点数.边数以及所需要增加的流量. 接下来的M行每行包含四个整数\(u,v,C,W\),表示一条从u到v,容量为C,扩容费用为W的边. 输出格式 输出文件一行包含两个整数,分别表示问题1和问题2的答案. 利用残余网

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

火星探险问题(luogu) Solution 容易想到费用流 为解决点权问题,将一个不是障碍的点 i 拆成两个点 ai,bi 从 ai 向 bi 连一条流量为正无穷(表示可以无限次经过),费用为 0(表示这些经过没有收益)的边 若点 i 是石块,则再从 ai 向 bi 连一条流量为1(表示只能经过一次),费用为 1(表示这次经过收益为 1)的边 若点 i 可以到点 j 且 i 和 j 都不是障碍,则从 bi 向 aj 连一条流量为正无穷,费用为 0 的边 从起点向 a1 连一条流量为探测车数,费

Luogu1006 传纸条 与 Luogu P2045方格取数加强版 (费用流)

Luogu1006 传纸条 与 Luogu P2045方格取数加强版 其实就是这几道题 在一个有m*n 个方格的棋盘中 每个方格中有一个正整数 现要从在方格中从左上角到右下角取数,只能向右或向下走 每走到一个格子就可以把这个位置上的数取走(下次经过就没有了) 1.让你走1次,求取出的数的总和最大是多少 2.让你走2次,求取出的数的总和最大是多少 3.让你走k次,求取出的数的总和最大是多少 对于第一问,十分显然. 设\(f[i][j]\)表示\(i\)行\(j\)列的最大价值,转移即可. 第二问,

有上下界的、有多组源汇的、网络流、费用流问题

先默认读者有基础的网络流以及费用流的知识前置 1.有上下界无源点汇点的可行流问题: 在本文中指: 原图中没有任何一个点可以凭空产生流量,亦没有任何一个点可以凭空消灭流量: 存在边既有流量上界又有流量下界: 求每条边流量的一组可行解: 满足每个点的入流量等于出流量: 由题意可见本题的图中有环,于是此类问题也被称作循环流: 这里给出的解法是将本题转换为一道普通的有上界最大流问题: 修改本题原图中每条边的流量下界为0,上界为原上界-原下界: 视为该边现在已经拥有了等同于该边流量下界的基础流量了, 然而

[网络流24题] 餐巾计划问题 [费用流]

题面: https://www.luogu.org/problemnew/show/P1251 思路: 这道题乍一看,可以跑上下界费用流 代码量.难度 -> inf 其实不然,我们可以用费用流的特殊处理去掉下界 观察题目,每天要求有ri块餐巾 首先,有贪心如下: 当且仅当每天可供使用的餐巾正好满足需求时,可以有最小费用 证明:若某一天有多一块餐巾,则其根本来源一定是买多了,而且在这块餐巾参与的周转中还消费了一些清洗费用,同时它造成其余的日子里也会有餐巾被闲置 因此首先把题目转化为"每天正好

【网络流24题】No.19 负载平衡问题 (费用流)

[题意] G 公司有 n 个沿铁路运输线环形排列的仓库, 每个仓库存储的货物数量不等. 如何用最少搬运量可以使 n 个仓库的库存数量相同.搬运货物时,只能在相邻的仓库之间搬运. 输入文件示例input.txt517 9 14 16 4 输出文件示例output.txt11 [分析] 其实我觉得这题可以贪心啊..n^2贪心??.没细想.. 打的是费用流.. 大概这样建图: 懒得写了..凌乱之美.. 求满流费用.. 1 #include<cstdio> 2 #include<cstdlib&

POJ 3422 kaka&#39;s matrix trvals(费用流)

#include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <set> #include <map> #include <cma

hdu 2448 Mining Station on the Sea【网络费用流】

Mining Station on the Sea Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2371    Accepted Submission(s): 732 Problem Description The ocean is a treasure house of resources and the development