zoukankan      html  css  js  c++  java
  • [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;
    }
    
  • 相关阅读:
    dom4j修改,获取,增加xml中某个元素的属性值
    SVN功能详解
    采用RPC方式和document方式 开发Axis2的WebService客户端
    记录我电脑的环境变量配置
    Java float保留两位小数或多位小数
    c#中获取服务器IP,客户端IP以及Request.ServerVariables详细说明
    说说Java观察者模式
    2018第12周总结
    聊聊Java反射
    Java注解总结2
  • 原文地址:https://www.cnblogs.com/rui-4825/p/13965281.html
Copyright © 2011-2022 走看看