#75-【Dinic】复杂的大门

版权声明:反正也没有人会转,下一个 https://blog.csdn.net/drtlstf/article/details/82192180

Description

你去找某bm玩,到了门口才发现要打开他家的大门不是一件容易的事……

他家的大门外有n个站台,用1到n的正整数编号。你需要对每个站台访问一定次数以后大门才能开启。站台之间有m个单向的传送门,通过传送门到达另一个站台不需要花费任何代价。而如果不通过传送门,你就需要乘坐公共汽车,并花费1单位的钱。值得庆幸的是,任意两个站台之间都有公共汽车直达。

现在给你每个站台必须访问的次数Fi,对于站台i,你必须恰好访问Fi次(不能超过)。

我们用u、v、w三个参数描述一个传送门,表示从站台u到站台v有一个最多可以使用w次的传送门(不一定要使用w次)。值得注意的是,对于任意一对传送门(u1,v1)和(u2,v2),如果有u1,则有v1≤v2;如果有v1,则有u1≤u2;且u1=u2和v1=v2不同时成立。

你可以从任意的站台开始,从任意的站台结束。出发去开始的站台需要花费1单位的钱。你需要求出打开大门最少需要花费多少单位的钱。

 

Input

第一行包含两个正整数n、m,意义见题目描述。第二行包含n个正整数,第i个数表示Fi。接下来有m行,每行有三个正整数u、v、w,表示从u到v有一个可以使用w次的传送门。

Output

输出一行一个整数,表示打开大门最少花费的钱数。

Sample Input

4 3

5 5 5 5

1 2 1

3 2 1

3 4 1

Sample Output

17

HINT

 

有20%的数据满足n≤10,m≤50;对于所有的w、Fi,满足1≤w,Fi≤10。

有50%的数据满足n≤1000,m≤10000。

100%的数据满足1≤n≤10000,1≤m≤100000;对于所有的u、v,满足1≤u,v≤n,u≠v;

对于所有的w、Fi,满足1≤w,Fi≤50000。以上的每类数据中都存在50%的数据满足对于所有的w、Fi,有w=Fi=1。

就是建图麻烦......

#include <iostream>
#include <cstring>
#include <queue>

#define SIZE 21000
#define INF 1e+09

using namespace std;

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

vector<edge> graph[SIZE];
int cur[SIZE], depth[SIZE], sink;

bool bfs(void)
{
	queue<int> q;
	int u, i, v;
	
	memset(depth, -1, sizeof (depth));
	q.push(0);
	depth[0] = 0;
	while (!q.empty())
	{
		u = q.front();
		q.pop();
		if (u == sink)
		{
			return true;
		}
		for (i = 0; i < graph[u].size(); ++i)
		{
			v = graph[u][i].to;
			if ((depth[v] == -1) && (graph[u][i].cap > 0))
			{
				depth[v] = depth[u] + 1;
				q.push(v);
			}
		}
	}
	
	return false;
}

int dfs(int u, int flow)
{
	int i, v, ret = 0, delta;
	
	if ((!flow) || (u == sink))
	{
		return flow;
	}
	for (i = cur[u]; i < graph[u].size(); ++i)
	{
		cur[u] = i;
		edge &temp = graph[u][i];
		v = temp.to;
		if ((depth[v] == depth[u] + 1) && (temp.cap > 0))
		{
			delta = dfs(v, min(flow - ret, temp.cap));
			if (delta > 0)
			{
				ret += delta;
				temp.cap -= delta;
				graph[v][temp.reverse].cap += delta;
				if (ret == flow)
				{
					return ret;
				}
			}
		}
	}
	
	return ret;
}

int dinic(void) // Dinic算法
{
	int ret = 0, delta;
	
	while (bfs())
	{
		memset(cur, 0, sizeof (cur));
		delta = dfs(0, INF);
		if (!delta)
		{
			return ret;
		}
		ret += delta;
	}
	
	return ret;
}

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

int main(int argc, char** argv)
{
	int i, n, m, u, v, w, tot = 0;
	
	scanf("%d%d", &n, &m);
	sink = n + n + 1;
	for (i = 1; i <= n; ++i) // 建图
	{
		scanf("%d", &u);
		tot += u;
		addedge(0, i, u);
		addedge(n + i, sink, u);
	}
	while (m--)
	{
		scanf("%d%d%d", &u, &v, &w);
		addedge(u, n + v, w);
	}
	
	printf("%d", tot - dinic());
	
	return 0;
}

 

猜你喜欢

转载自blog.csdn.net/drtlstf/article/details/82192180
75