#85-【最小费用最大流+拆点容量限制】长城

Description

      长城表示为5行n列的网格,其中有些点要收费。收费点用一个数字表示所收的金额。有些人想要穿越长城,就是从第1列走到第n列,同时希望费用最小。出发时,所有人都在第1列上,用一个'@'表示。第一列上所有点的收费都为0.他们能水平或垂直地走,并且每个人都不会经过其他人已经走过的点。

【输入格式】

       第1行:一个整数 n (3 ≤ n ≤ 1000),表示列数,n为0时,表示输入结束

接下来5行,每行有n个字符,每个字符表示该点所收的费用。第1列上为'@'的位置表示某个人的位置,总是会有3个'@'.

【输出格式】

        第1行:一个整数,表示3个人穿越长城的最小费用

【输入样例】

27

@00100000000000102000000000

@00100000000000102111000000

000010000000011002110000000

@00011110000100002111000000

000000000011100002000000000

3

@10

@00

@00

000

000

12

024841026058

@03990540049

@01108404608

030789005500

@95750159143

0

【输出样例】

13

1

101

 

测试数据1的图示

#85-【最小费用最大流+拆点容量限制】长城_第1张图片

网上没有答案qaq

不过仔细想,建图也挺简单的嘛

#include 
#include 
#include 

#define SIZE 6500
#define INF 1e+09

using namespace std;

struct edge
{
	int to, cap, cost, reverse;
};

vector graph[SIZE];
int pre[SIZE], dis[SIZE], edgeindex[SIZE], sink, _cost[6][SIZE];
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
bool inqueue[SIZE];

bool spfa(int s)
{
	queue q;
	int u, v, i;
	
	memset(pre, -1, sizeof (pre));
	for (i = 0; i < SIZE; ++i)
	{
		dis[i] = INF;
	}
	memset(edgeindex, -1, sizeof (edgeindex));
	memset(inqueue, false, sizeof (inqueue));
	dis[s] = 0;
	q.push(s);
	inqueue[s] = true;
	while (!q.empty())
	{
		u = q.front();
		q.pop();
		inqueue[u] = false;
		for (i = 0; i < graph[u].size(); ++i)
		{
			v = graph[u][i].to;
			if ((graph[u][i].cap > 0) && (dis[v] > dis[u] + graph[u][i].cost))
			{
				dis[v] = dis[u] + graph[u][i].cost;
				pre[v] = u;
				edgeindex[v] = i;
				if (!inqueue[v])
				{
					q.push(v);
					inqueue[v] = true;
				}
			}
		}
	}
	
	return (dis[sink] != INF);
}

int mincostmaxflow(int s) // 求最小费用最大流
{
	int u, v, maxflow = 0, delta, mincost = 0, i;
	
	while (spfa(s))
	{
		delta = INF;
		for (v = sink; v != s; v = u)
		{
			u = pre[v];
			i = edgeindex[v];
			delta = min(delta, graph[u][i].cap);
		}
		for (v = sink; v != s; v = u)
		{
			u = pre[v];
			i = edgeindex[v];
			mincost += delta * graph[u][i].cost;
			graph[u][i].cap -= delta;
			graph[v][graph[u][i].reverse].cap += delta;
		}
		maxflow += delta;
	}
	
	return mincost;
}

void addedge(int u, int v, int cap, int cost)
{
	graph[u].push_back({v, cap, cost, graph[v].size()});
	graph[v].push_back({u, 0, -cost, graph[u].size() - 1});
	
	return;
}

int main(int argc, char** argv)
{
	int n, u, v, i, j, k, r, c, temp;
	char ch;
	
	scanf("%d", &n);
	temp = n * 5;
	sink = n * 10 + 1;
	for (i = 1; i <= 5; ++i) // 以下建图
	{
		addedge(i * n, sink, 1, 0); // 连终点
		for (j = 1; j <= n; ++j)
		{
			addedge((i - 1) * n + j, temp + (i - 1) * n + j, 1, 0); // 拆点容量限制,即一个格子只能走一个人
			cin >> ch;
			if (ch == '@')
			{
				addedge(0, (i - 1) * n + 1, 1, 0); // 连起点
			}
			else
			{
				_cost[i][j] = ch - '0';
			}
		}
	}
	for (i = 1; i <= 5; ++i)
	{
		for (j = 1; j <= n; ++j)
		{
			for (k = 0; k < 4; ++k)
			{
				r = i + dx[k];
				c = j + dy[k];
				if (((!r) || (r > 5)) || ((!c) || (c > n)))
				{
					continue;
				}
				addedge(temp + (i - 1) * n + j, (r - 1) * n + c, 1, _cost[r][c]); // 连边
			}
		}
	}
	
	printf("%d", mincostmaxflow(0));
	
	return 0;
}

 

你可能感兴趣的:(刷题,gdgzoi刷题)