• 杨柳


    题目

    传送门

    题意

    给出一个(r * c)的矩阵, 有(n)颗棋子, 给出棋子的初始位置, 有(n)个目标点, 有些位置不能走, 位于((x, y))的棋子, 可以一步走到((x + a, y + b)), ((x - a, y + b)), ((x + a, y - b)), ((x - a, y + b)), ((x + b, y + a)), ((x + b, y - a)), ((x - b, y + a)). ((x - b, y - a)), 求每个棋子都走到目标点的最短时间。

    题解

    由源点向棋子的初始位置连容量为(1)费用为(0)的边
    由目标位置向汇点连容量为(1)用为(0)的边
    对于每一个能走的点, 向他能够一步走到的点连容量为(infty)费用为(1)的边
    然后跑费用流

    此题卡常, 如果用MCMF的话要多路增广才能过。

    代码

    #include <iostream>
    #include <cstdlib>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    
    const int N = 10010, M = 160010;
    
    const int INF = 0x2A2A2A2A;
    
    
    struct edge
    {
    	int from, to, flow, cap, dis;
    	edge() { }
    	edge(int _1, int _2, int _3, int _4, int _5) : from(_1), to(_2), flow(_3), cap(_4), dis(_5) { }
    };
    
    struct MCMF
    {
    	int head[N], nxt[M], tot;
    	edge edges[M];
    
    	inline void init()
    	{
    		memset(head, -1, sizeof(head));
    		tot = 0;
    	}
    	
    	inline void add_edge(int x, int y, int z, int k)
    	{
    		edges[tot] = edge(x, y, 0, z, k);
    		nxt[tot] = head[x];
    		head[x] = tot++;
    		edges[tot] = edge(y, x, 0, 0, -k);
    		nxt[tot] = head[y];
    		head[y] = tot++;
    	}
    
    	int s, t;
    
    	int L, R;
    
    	int cost;
    	int flow;
    
    	int dist[N];
    	bool inq[N];
    
    	bool SPFA()
    	{
    		memset(dist + L, 127 / 3, sizeof(int) * (R - L + 1));
    		memset(inq + L, 0, sizeof(int) * (R - L + 1));
    		
    		queue<int> q;
    		q.push(s);
    		dist[s] = 0;
    		inq[s] = 1;
    		
    		while (!q.empty())
    		{
    			int x = q.front(); q.pop();
    			inq[x] = 0;
    			cur[x] = head[x];
    			for (register int i = head[x]; ~i; i = nxt[i])
    			{
    				edge & e = edges[i];
    				if (e.flow < e.cap && dist[e.to] > dist[x] + e.dis)
    				{
    					dist[e.to] = dist[x] + e.dis;
    					if (!inq[e.to])
    						inq[e.to] = 1, q.push(e.to);
    				}
    			}
    		}
    		
    		return dist[t] != INF;
    	}
    	
    	bool vis[N];
    	
    	int cur[N];
    	
    	int dfs(int x, int a)
    	{
    		if (x == t || a == 0) return a;
    		
    		vis[x] = 1;
    		
    		int flow = 0, f;
    		
    		for (int & i = cur[x]; ~i; i = nxt[i])
    		{
    			edge & e = edges[i];
    			if (vis[e.to]) continue;
    			if (dist[e.to] == dist[x] + e.dis && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0)
    			{
    				e.flow += f;
    				edges[i^1].flow -= f;
    				cost += e.dis * f;
    				flow += f;
    				a -= f;
    				if (a == 0) break;
    			}
    		}
    		
    		vis[x] = 0;
    		
    		return flow;
    	}
    
    	pair<int, int> mincostmaxflow(int _s, int _t)
    	{
    		cost = 0;
    		flow = 0;
    		s = _s, t = _t;
    		while (SPFA())
    			flow += dfs(s, INF);
    		return make_pair(flow, cost);
    	}
    } solve;
    
    
    char mp[110][110];
    
    int n, m;
    int k, A, B;
    
    
    inline int getid(int x, int y) { return (x-1) * m + y; }
    
    
    int main()
    {
    	scanf("%d %d %d %d %d", &n, &m, &k, &A, &B);
    	
    	int S = n * m + 1, T = n * m + 2;
    	
    	solve.init();
    	solve.L = 0, solve.R = n * m + 2;
    	
    	for (register int i = 1; i <= n; i++)
    		scanf("%s", mp[i] + 1);
    	
    	for (register int i = 1; i <= k; i++)
    	{
    		int x, y;
    		scanf("%d %d", &x, &y);
    		solve.add_edge(getid(x, y), T, 1, 0);
    	}
    	
    	for (register int i = 1; i <= k; i++)
    	{
    		int x, y;
    		scanf("%d %d", &x, &y);
    		solve.add_edge(S, getid(x, y), 1, 0);
    	}
    	
    	for (register int x = 1; x <= n; x++)
    		for (register int y = 1; y <= m; y++)
    			if (mp[x][y] == '.')
    			{
    				if (x + A <= n && y + B <= m && mp[x + A][y + B] == '.')
    				{	solve.add_edge(getid(x, y), getid(x + A, y + B), INF, 1);
    					solve.add_edge(getid(x + A, y + B), getid(x, y), INF, 1);
    				}
    				if (x + A <= n && y - B >= 1 && mp[x + A][y - B] == '.')
    				{	solve.add_edge(getid(x, y), getid(x + A, y - B), INF, 1);
    					solve.add_edge(getid(x + A, y - B), getid(x, y), INF, 1);
    				}
    				if (x + B <= n && y + A <= m && mp[x + B][y + A] == '.')
    				{	solve.add_edge(getid(x, y), getid(x + B, y + A), INF, 1);
    					solve.add_edge(getid(x + B, y + A), getid(x, y), INF, 1);
    				}
    				if (x + B <= n && y - A >= 1 && mp[x + B][y - A] == '.')
    				{	solve.add_edge(getid(x, y), getid(x + B, y - A), INF, 1);
    					solve.add_edge(getid(x + B, y - A), getid(x, y), INF, 1);
    				}
    			}
    	
    	pair<int, int> Ans = solve.mincostmaxflow(S, T);
    	
    	if (Ans.first == k) printf("%d
    ", Ans.second);
    	else puts("-1");
    	
    	return 0;
    }
    
  • 相关阅读:
    正斜杠/和反斜杠的区别
    Ghost文件封装说明
    装机自动化脚本介绍
    ubuntu 11.04侧边栏怎么添加图标
    samba的安装和配置
    vim使用大全
    ubuntu中运行python脚本
    ubuntu中使用usb-creator制作live usb
    ubuntu中安装ftp服务器
    ubuntu命令查询版本和内核版本
  • 原文地址:https://www.cnblogs.com/2016gdgzoi509/p/10022588.html
Copyright © 2020-2023  润新知