• [ICPC-Beijing 2006]狼抓兔子


    Description
    现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,
    而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:
    image.png
    左上角点为((1,1)), 右下角点为((N,M))(上图中(N=3),(M=4)).有以下三种类型的道路:

    • ((x,y) ightleftharpoons(x+1,y))
    • ((x,y) ightleftharpoons(x,y+1))
    • ((x,y) ightleftharpoons(x+1,y+1))

    道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的。左上角和右下角为兔子的两个窝,开始时所有的兔子都聚集在左上角((1,1))的窝里,现在它们要跑到右下角((N,M))的窝中去,狼王开始伏击这些兔子。当然为了保险起见,如果一条道路上最多通过的兔子数为(K),狼王需要安排同样数量的(K)只狼,才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的狼的数量要最小。因为狼还要去找喜羊羊麻烦。

    Input
    第一行两个整数(N,M),表示网格的大小。
    接下来分三部分。
    第一部分共 (N) 行,每行 (M-1) 个数,表示横向道路的权值。
    第二部分共 (N-1) 行,每行 (M) 个数,表示纵向道路的权值。
    第三部分共 (N-1) 行,每行 (M-1) 个数,表示斜向道路的权值。

    Output
    输出一个整数,表示参与伏击的狼的最小数量。

    Sample Input
    3 4
    5 6 4
    4 3 1
    7 5 3
    5 6 7 8
    8 7 6 5
    5 5 5
    6 6 6

    Sample Output
    14

    HNIT
    对于全部的测试点,保证(3 leqslant N,M leqslant 1000),所有道路的权值均为不超过(10^6)的正整数。


    这题一看就是个最小割板子题,不过当你笑嘻嘻敲一个Dinic上去后肯定会得到TLE的结果(卡常大佬不在此列)

    那就换个方法,这题求最小割肯定是没错的,关键是怎么快速的求。

    可以发现,这个图的边是没有交叉的,因此它是一张平面图,因此,我们可以使用一个性质:平面图最小割=对偶图最短路

    证明过程可以画图理解,对偶图定义请自行查询,这里不再赘述

    找对建图方法即可

    /*program from Wolfycz*/
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define inf 0x7f7f7f7f
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    inline char gc(){
    	static char buf[1000000],*p1=buf,*p2=buf;
    	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
    }
    template<typename T>inline T frd(T x){
    	int f=1; char ch=gc();
    	for (;ch<'0'||ch>'9';ch=gc())	if (ch=='-')    f=-1;
    	for (;ch>='0'&&ch<='9';ch=gc())	x=(x<<1)+(x<<3)+ch-'0';
    	return x*f;
    }
    template<typename T>inline T read(T x){
    	int f=1;char ch=getchar();
    	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')	f=-1;
    	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
    	return x*f;
    }
    inline void print(int x){
    	if (x<0)    putchar('-'),x=-x;
    	if (x>9)	print(x/10);
    	putchar(x%10+'0');
    }
    template<typename T>inline T min(T x,T y){return x<y?x:y;}
    template<typename T>inline T max(T x,T y){return x>y?x:y;}
    template<typename T>inline T swap(T &x,T &y){T t=x; x=y,y=t;}
    const int N=2e6;
    struct S1{
    	#define ls (p<<1)
    	#define rs (p<<1|1)
    	#define fa (p>>1)
    	struct S2{
    		int x,v;
    		S2(){x=v=0;}
    		S2(int _x,int _v){x=_x,v=_v;}
    		void insert(int _x,int _v){x=_x,v=_v;}
    		bool operator <(const S2 &_x){return v<_x.v;}
    	}Q[N+10];
    	int tot;
    	S1(){tot=0;}
    	void clear(){tot=0;}
    	void insert(int x,int v){
    		Q[++tot].insert(x,v);
    		int p=tot;
    		while (Q[p]<Q[fa])	swap(Q[p],Q[fa]),p=fa;
    	}
    	S2 Query(){
    		S2 Ans=Q[1]; Q[1]=Q[tot--];
    		int p=1,son;
    		while (ls<=tot){
    			if (rs>tot||Q[ls]<Q[rs])	son=ls;
    			else	son=rs;
    			if (Q[son]<Q[p])	swap(Q[p],Q[son]),p=son;
    			else	break;
    		}
    		return Ans;
    	}
    	bool empty(){return !tot;}
    	#undef ls
    	#undef rs
    	#undef fa
    }Heap;
    bool vis[N+10];
    int now[N+10],pre[(N<<3)+10],child[(N<<3)+10],val[(N<<3)+10],dis[N+10],tot;
    void join(int x,int y,int v){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=v;}
    void insert(int x,int y,int v){join(x,y,v),join(y,x,v);}
    void Dijkstra(int S){
    	memset(dis,63,sizeof(dis));
    	Heap.insert(S,dis[S]=0);
    	while (!Heap.empty()){
    		int Now=Heap.Query().x;
    		if (vis[Now])	continue;
    		vis[Now]=1;
    		for (int p=now[Now],son=child[p];p;p=pre[p],son=child[p]){
    			if (dis[son]>dis[Now]+val[p]){
    				dis[son]=dis[Now]+val[p];
    				Heap.insert(son,dis[son]);
    			}
    		}
    	}
    }
    int main(){
    	int n=read(0),m=read(0),S=(n-1)*(m-1)*2+1,T=S+1;
    	for (int i=1;i<=n;i++){
    		for (int j=1;j<m;j++){
    			int V=read(0);
    			if (i==1)	insert(S,j,V);
    			if (i==n)	insert(S+j-m,T,V);
    			if (i!=1&&i!=n)	insert((i-1)*(m-1)+j,(n+i-3)*(m-1)+j,V);
    		}
    	}
    	for (int i=1;i<n;i++){
    		for (int j=1;j<=m;j++){
    			int V=read(0);
    			if (j==1)	insert((n+i-2)*(m-1)+1,T,V);
    			if (j==m)	insert(i*(m-1),S,V);
    			if (j!=1&&j!=m)	insert((i-1)*(m-1)+j-1,(n+i-2)*(m-1)+j,V);
    		}
    	}
    	for (int i=1;i<n;i++){
    		for (int j=1;j<m;j++){
    			int V=read(0);
    			insert((i-1)*(m-1)+j,(n+i-2)*(m-1)+j,V);
    		}
    	}
    	Dijkstra(S);
    	printf("%d
    ",dis[T]);
    	return 0;
    }
    
  • 相关阅读:
    头文件stdio与stdlib.h的区别
    宝塔利用git+ webhooks 实现git更新远程同步Linux服务器
    Linux源码安装步骤
    Promise.all和Promise.race区别,和使用场景
    vue显示富文本
    Js实现将html页面或div生成图片
    JS
    关于Swiper和vue数据顺序加载问题处理
    php 数据库备份(可用作定时任务)
    js async await 终极异步解决方案
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/13837965.html
Copyright © 2020-2023  润新知