UVALive 3661 最小割转化为最短路径

题意:动物逃跑,从左上跑到右下角,逃跑的路径是一个grid的边,现在动物园的工作人员要去拦截。input给出了grid每条路径拦截所需要的cost,题目要求拦截成功最小的成本。

经典的最小割问题,但是400*400个点太大了,所以不能直接这么做

lrj给出的方法是动物要从左上跑到右下,所有我们考虑怎么摆障碍物就可以了,思考可以知道,只要做左/下->右/上的连续拦截边,就可以将所有可行路径分割开。如下图(偷了别人博客的图。。。)

这张图其实是hdu3870的图,题意差不多,但是没有斜边,所以少了两倍的点,建图也简单的多。从左/下到右/上的拦截边可以这样考虑,增加s源点,ed终点,最在要求拦截的成功的最小成本就是从s到t可最短可行边,dij模板套一下就可以了

难点在思考和建图,边转化为点,重新建图刚开始看还是挺毁我三观的

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <stack>
#include <string>
#include <queue>
#include <vector>
#include <algorithm>
#include <ctime>
using namespace std;

#define EdsonLin

#ifdef EdsonLin
#define debug(...) fprintf(stderr,__VA_ARGS__)
#else
#define debug(...)
#endif //EdsonLin

typedef long long ll;
typedef double db;
const int inf = 0x3f3f3f;
const int MAXN = 1e3;
const int MAXNN = 2e6+100;
//const int MAXM = 1e6;
//const int MAXM = 3e4+100;
const int MOD = 1000000007;
const db eps = 1e-3;
#define PB push_back
#define UP(i) ((i)<<1)
#define DOWN(i) ((UP(i))-1)

struct dij{
    int n,m;
    int first[MAXNN];
    struct edge{
        int st,to,next,dist;
    };
    vector<edge>e;
    int top;
    int d[MAXNN]; //s到各节点的距离
    int done[MAXNN]; //是否已经被永久标记
    int p[MAXNN]; //记录上一条边
    struct heapnode{
        int st;
        int dist;
        bool operator < (const heapnode& rhs) const {
            return dist>rhs.dist;
        }
    };
    void init(int n){
        this->n = n;
        memset(first,-1,sizeof(first));
        top = 0;
        e.clear();
    }
    void addedge(int u,int v,int dist){
        /*e[top].st = u;
        e[top].to = v;
        e[top].dist = dist;
        e[top].next = first[u];
        first[u] = top++;*/
        edge a;
        a.st = u;
        a.to = v;
        a.dist = dist;
        a.next  = first[u];
        e.PB(a);
        first[u] = top++;
        //cout<<first[u]<<endl;
        //cout<<top<<endl;
    }

    void pqdij(int s){
        priority_queue<heapnode>Q;
        heapnode a;
        for(int i=0;i<n;i++)
            d[i] = inf;
        d[s] = 0;
        memset(done,0,sizeof(done));
        a.dist = 0;
        a.st = s;
        Q.push(a);
        while(!Q.empty()){
            heapnode x = Q.top();
            Q.pop();
            int u = x.st;
            if(done[u])continue;
            done[u] = 1;
            for(int i=first[u];i!=-1;i=e[i].next){
                if(d[e[i].to]>d[u]+e[i].dist){
                    d[e[i].to] = d[u] + e[i].dist;
                    p[e[i].to] = i;
                    a.dist = d[e[i].to];
                    a.st = e[i].to;
                    Q.push(a);
                }
            }
        }
    }
}solver;

int hor[MAXN][MAXN],vec[MAXN][MAXN],dia[MAXN][MAXN];
int readint(){int x;scanf("%d",&x);return x;}

int main()
{
    #ifdef EdsonLin
        //freopen("1.in","r",stdin);
        //freopen("1.out","w",stdout);
        int _time_ed = clock();
    #endif //EdsonLin
    int mc=0,n,m;
    while(scanf("%d%d",&n,&m)&&n){
        for(int i=1;i<=n;i++){
            for(int j=1;j<m;j++)
                hor[i][j] = readint();
        }
        for(int i=1;i<n;i++){
            for(int j=1;j<=m;j++)
                vec[i][j] = readint();
        }
        for(int i=1;i<n;i++){
            for(int j=1;j<m;j++)
                dia[i][j] = readint();
        }
        int st=0,ed = (n-1)*(m-1)*2+1;
        solver.init(ed+1);
        for(int i=1;i<n;i++){
            for(int j=1;j<m;j++){
                if(i==1){
                    solver.addedge(2*(i-1)*(m-1)+UP(j),ed,hor[i][j]);
                    solver.addedge(ed,2*(i-1)*(m-1)+UP(j),hor[i][j]);
                }
                if(i==n-1){
                    solver.addedge(st,2*(i-1)*(m-1)+DOWN(j),hor[i+1][j]);
                    solver.addedge(2*(i-1)*(m-1)+DOWN(j),st,hor[i+1][j]);
                }
                if(i!=n-1){
                    solver.addedge(2*(i-1)*(m-1)+DOWN(j),2*(i)*(m-1)+UP(j),hor[i+1][j]);
                    solver.addedge(2*i*(m-1)+UP(j),2*(i-1)*(m-1)+DOWN(j),hor[i+1][j]);
                }
                if(j==1){
                    solver.addedge(st,2*(i-1)*(m-1)+DOWN(j),vec[i][j]);
                    solver.addedge(2*(i-1)*(m-1)+DOWN(j),st,vec[i][j]);
                }
                if(j!=m-1){
                    solver.addedge(2*(i-1)*(m-1)+DOWN(j),2*(i-1)*(m-1)+UP(j),dia[i][j]);
                    solver.addedge(2*(i-1)*(m-1)+UP(j),2*(i-1)*(m-1)+DOWN(j),dia[i][j]);

                    solver.addedge(2*(i-1)*(m-1)+UP(j),2*(i-1)*(m-1)+DOWN(j+1),vec[i][j+1]);
                    solver.addedge(2*(i-1)*(m-1)+DOWN(j+1),2*(i-1)*(m-1)+UP(j),vec[i][j+1]);
                }
                if(j==m-1){
                    solver.addedge(2*(i-1)*(m-1)+DOWN(j),2*(i-1)*(m-1)+UP(j),dia[i][j]);
                    solver.addedge(2*(i-1)*(m-1)+UP(j),2*(i-1)*(m-1)+DOWN(j),dia[i][j]);

                    solver.addedge(2*(i-1)*(m-1)+UP(j),ed,vec[i][j+1]);
                    solver.addedge(ed,2*(i-1)*(m-1)+UP(j),vec[i][j+1]);
                }
            }
        }
        solver.pqdij(st);
        printf("Case %d: Minimum = %d\n",++mc,solver.d[ed]);
    }

    #ifdef EdsonLin
        debug("time: %d\n",int(clock()-_time_ed));
    #endif //EdsonLin
   // cout << "Hello world!" << endl;
    return 0;
}

时间: 2024-08-07 23:56:15

UVALive 3661 最小割转化为最短路径的相关文章

hdu 3870 最小割转化为最短路径2

Catch the Theves Problem Description A group of thieves is approaching a museum in the country of zjsxzy,now they are in city A,and the museum is in city B,where keeps many broken legs of zjsxzy.Luckily,GW learned the conspiracy when he is watching s

【Algorithm】平面图最小割转最短路

杭电上碰巧有几道求最小割的题目,用网络流解超时.通过离散数学中的一些知识可以将平面图最小割转化为最短路径,通过最短路解提高效率.这个转化过程很简单,但是很巧妙,详细内容可以参考<浅析最大最小定理在信息学竞赛中的应用>. 1. [HDU] 3870 Catch the Theves有一个网格拓扑,每条边都表示有$A_{ij}$个小偷,现在希望对其中一条边部署警察,使得小偷不可能偷到右下角的财宝.求至少需要多少个警察?这题是个挺有实际意义的题目,基本思路也很简单.因为题目给定小偷都从左上角出发向右

BZOJ_1001_狼抓兔子(平面图求最小割+对偶图求最短路)

描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1001 分析 平面图求最小割,转化成对偶图求最短路,经典. 注意: 1.优先队列是个大根堆. 2.Dijkstra可以带一个vis数组,也可以不带,因为一个点出来以后,它更新的的点和原本就在队列里的点都比它大,所以它不可能被更新得更小,之后这个点再出队时情况不比第一次更优,所以出队也不会有操作. 3.双向边,数组要开够(貌似不是第一次犯这个错误). 4.网上有人说m==1||n==1的情况可以

Vijos1734 NOI2010 海拔 平面图最小割

建立平面图的对偶图,把最小割转化成最短路问题 Dijkstra算法堆优化 (被输入顺序搞WA了好几次T_T) 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue> 5 6 const int maxN=502; 7 const int maxV=maxN*maxN; 8 const int inf=0x3f3f3f3f; 9 10 struct E

UVALive - 3661 Animal Run (平面图+最小割+对偶图+最短路)

题目大意:有很多只小动物要从左上角跑到右下角,给出每条线路所需的人手,问至少需要多少人手,才能将所有动物抓住 解题思路:最小割,就是最小割,但是用最大流处理不了,边太多了 具体可以参考算法合集之<浅析最大最小定理在信息学竞赛中的应用> 知道了这个后,这题估计就可以解了 给出我的建图方式 将每一个小三角形从左往右,从上到下依次编号为1-2-3.. 每行的同一个三角行的编号差就是2 * (m - 1) 如图 #include <cstdio> #include <cstring&

tyvj P1209 - 拦截导弹 平面图最小割&amp;&amp;模型转化

P1209 - 拦截导弹 From admin    Normal (OI)总时限:6s    内存限制:128MB    代码长度限制:64KB 背景 Background 实中编程者联盟为了培养技术精湛的后备人才,必须从基础题开始训练. 描述 Description 某国为了防御敌国的导弹袭击,研发出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试验阶段,所以只有

UVALive 5905 Pool Construction 最小割,s-t割性质 难度:3

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3916 这道题要求一种填充+挖坑+建屏障的方法,使得这块土地上的所有坑和草地之间都有屏障,挖坑花费d每块,填充花费f每块,建屏障花费b每两块之间,注意并不要求一定有坑,但是外围一圈要一定没有坑,所以需要预先填充好 令st代表平地,ed代表坑,边权为花费,那么本题是要求一个st-

UVALive 5099 Nubulsa Expo 全局最小割 非网络流 n^3

题目链接:点击打开链接 题意: 给定n个点m条无向边 源点S 下面m行给出无向边以及边的容量. 问: 找一个汇点,使得图的最大流最小. 输出最小的流量. 思路: 最大流=最小割. 所以题意就是找全局最小割. 和源点无关,因为不关心源点在哪个点集里. 模版题: O(n^3) #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std

UVALive 7264 Kejin Game(最小割)

题目地址:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=5276 思路:最小割.将每个点拆成 i 和 i',设一个源点与汇点. 1.对于边i--->j,连边i'--->j,容量为对应边的费用. 2.源点到 i 连边,容量为满足条件后购买 i 的费用. 3.对于 i 和 i' 连边,容量为直接购买 i 的费用. 4