• [ICPC-Beijing 2006]狼抓兔子(网络最大流+最短路)


    题目描述

    现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:

    左上角点为 (1,1), 右下角点为 (N,M) (上图中 N=3, M=4).有以下三种类型的道路:

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

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

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

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

    输入格式

    第一行两个整数 N,M,表示网格的大小。

    接下来分三部分。

    第一部分共 N 行,每行 M−1 个数,表示横向道路的权值。

    第二部分共 N-1 行,每行 M 个数,表示纵向道路的权值。

    第三部分共 N−1 行,每行 M-1 个数,表示斜向道路的权值。

    输出格式

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

    输入输出样例

    输入

    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

    输出

    14

    数据规模与约定

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

    Solution

    显然
    暴力建图直接跑就,,,
    但是数据随便卡(TLE)
    但是正确性是没有任何问题的
    注意建边的时候二维转换一维的对应关系

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #define min(a, b) ({register int AA = a, BB = b; AA < BB ? AA : BB;})
    using namespace std;
    
    inline int read(){
    	int x = 0, w = 1;
    	char ch = getchar();
    	for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
    	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
    	return x * w;
    }
    
    const int ss = 3000010;
    
    struct node{
    	int to, nxt, w;
    }edge[ss << 2];
    
    int head[ss], tot = 1;
    inline void add(register int u, register int v, register int w){
    	edge[++tot].to = v;
    	edge[tot].nxt = head[u];
    	edge[tot].w = w;
    	head[u] = tot;
    }
    
    int dis[ss], cur[ss];
    int n, m, s, t;
    bool vis[ss];
    queue<int> q;
    inline bool spfa(register int s){
    	for(register int i = 0; i <= t; i++)
    		dis[i] = 0x3f3f3f3f, cur[i] = head[i];
    	dis[s] = 0;
    	q.push(s);
    	while(!q.empty()){
    		register int u = q.front();
    		q.pop();
    		vis[u] = 0;
    		for(register int i = head[u]; i; i = edge[i].nxt){
    			register int v = edge[i].to;
    			if(dis[v] > dis[u] + 1 && edge[i].w){
    				dis[v] = dis[u] + 1;
    				if(!vis[v]) q.push(v), vis[v] = 1;
    			}
    		}
    	}
    	return dis[t] != 0x3f3f3f3f;
    }
    
    inline int dfs(register int u, register int flow){
    	register int res = 0;
    	if(u == t) return flow;
    	for(register int i = cur[u]; i; i = edge[i].nxt){
    		cur[u] = i;
    		register int v = edge[i].to;
    		if(dis[v] == dis[u] + 1 && edge[i].w){
    			if(res = dfs(v, min(flow, edge[i].w))){
    				edge[i].w -= res;
    				edge[i ^ 1].w += res;
    				return res;
    			}
    		}
    	}
    	return 0;
    }
    
    long long maxflow;
    inline long long dinic(){
    	register long long minflow = 0;
    	while(spfa(s)){
    		while(minflow = dfs(s, 0x7fffffff))
    			maxflow += minflow;
    	}
    	return maxflow;
    }
    
    inline int change(register int i, register int j){
    	return (i - 1) * m + j;
    }
    
    signed main(){
    	n = read(), m = read();
    	s = 1, t = n * m;
    	for(register int i = 1; i <= n; i++)
    		for(register int j = 1; j <= m - 1; j++){
    			//cout << change(i, j) << " " << change(i, j) + 1 << endl;
    			register int x = read();
    			add(change(i, j), change(i, j) + 1, x);
    			add(change(i, j) + 1, change(i, j), 0);
    			add(change(i, j) + 1, change(i, j), x);
    			add(change(i, j), change(i, j) + 1, 0);
    		}
    	for(register int i = 1; i <= n - 1; i++)
    		for(register int j = 1; j <= m; j++){
    			//cout << change(i, j) << " " << change(i, j) + m << endl;
    			register int x = read();
    			add(change(i, j), change(i, j) + m, x);
    			add(change(i, j) + m, change(i, j), 0);
    			add(change(i, j) + m, change(i, j), x);
    			add(change(i, j), change(i, j) + m, 0);
    		}
    	for(register int i = 1; i <= n - 1; i++)
    		for(register int j = 1; j <= m - 1; j++){
    			//cout << change(i, j) << " " << change(i, j) + m + 1 << endl;
    			register int x = read();
    			add(change(i, j), change(i, j) + m + 1, x);
    			add(change(i, j) + m + 1, change(i, j), 0);
    			add(change(i, j) + m + 1, change(i, j), x);
    			add(change(i, j), change(i, j) + m + 1, 0);
    		}
    	printf("%lld
    ", dinic());
    	return 0;
    }
    

    正解最短路
    从左下角向右上角拦截
    (Dij)
    一样的,注意建图的时候坐标转换

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    using namespace std;
    
    inline int read() {
        int x = 0, w = 1;
        char ch = getchar();
        for (; ch > '9' || ch < '0'; ch = getchar())
            if (ch == '-')
                w = -1;
        for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
        return x * w;
    }
    
    const int ss = 6003000;
    
    struct e {
        int to, w, nxt;
    } edge[ss << 2];
    
    int tot, head[ss];
    inline void add(int u, int v, int w) {
        edge[++tot].to = v;
        edge[tot].w = w;
        edge[tot].nxt = head[u];
        head[u] = tot;
    }
    
    struct node {
        int pos, dis;
        node(int a, int b) {
            pos = a;
            dis = b;
        }
        inline bool operator<(const node &x) const { return dis > x.dis; }
    };
    
    priority_queue<node> q;
    bool vis[ss];
    int dis[ss];
    
    inline void Dij(int s) {
        memset(dis, 0x3f, sizeof dis);
        memset(vis, 0, sizeof vis);
        dis[s] = 0;
        q.push(node(s, 0));
        while (!q.empty()) {
            node tmp = q.top();
            q.pop();
            int u = tmp.pos;
            if (vis[u])
                continue;
            vis[u] = 1;
            for (int i = head[u]; i; i = edge[i].nxt) {
                int v = edge[i].to;
                if (dis[v] > dis[u] + edge[i].w) {
                    dis[v] = dis[u] + edge[i].w;
                    q.push(node(v, dis[v]));
                }
            }
        }
    }
    
    int n, m, s, t;
    inline int id(register int x, register int y, register int op){
    	return (x - 1) * (m - 1) + y + op * (n - 1) * (m - 1);
    }
    
    signed main(){
    	n = read(), m = read();
    	s = 0 ,t = (n - 1) * (m - 1) * 2 + 1;
    	for(register int i = 1; i <= n; ++i){
    		for(register int j = 1; j < m; ++j){
    			register int x = read();
    			if(i == 1) add(id(i, j, 1), t, x), add(t, id(i, j, 1), x);
    			else if(i == n) add(id(i - 1, j, 0), s, x), add(s, id(i - 1, j, 0), x);
    			else add(id(i, j, 1), id(i - 1, j, 0), x), add(id(i - 1, j, 0), id(i, j, 1), x);
    		}
    	}
    	for(register int i = 1; i < n; ++i){
    		for(register int j = 1; j <= m; ++j){
    			register int x = read();
    			if(j == 1) add(id(i, j, 0), s, x), add(s, id(i, j, 0), x);
    			else if(j == m) add(id(i, j - 1, 1), t, x), add(t, id(i, j - 1, 1), x);
    			else add(id(i, j, 0), id(i, j - 1, 1), x), add(id(i, j - 1, 1), id(i, j, 0), x);
    		}
    	}
    	for(register int i = 1; i < n; ++i){
    		for(register int j = 1; j < m; ++j){
    			register int x = read();
    			add(id(i, j, 0), id(i, j, 1), x);
    			add(id(i, j, 1), id(i, j, 0), x);
    		}
    	}
    	Dij(s);
    	printf("%d
    ", dis[t]);
    	return 0;
    }
    
  • 相关阅读:
    element ui 表单清空
    element ui 覆盖样式 方法
    element ui 修改表单值 提交无效
    element ui 抽屉里的表单输入框无法修改值
    element ui 抽屉首次显示 闪烁
    css 左侧高度 跟随右侧内容高度 自适应
    PICNUF框架
    elementui 抽屉组件标题 出现黑色边框
    vue 子组件跨多层调用父组件中方法
    vue 编辑table 数据 未点击提交,table里的数据就发生了改变(深拷贝处理)
  • 原文地址:https://www.cnblogs.com/rui-4825/p/13965281.html
Copyright © 2020-2023  润新知