码迷,mamicode.com
首页 > 其他好文 > 详细

解题报告 之 HOJ2816 Power Line

时间:2015-04-24 09:05:28      阅读:129      评论:0      收藏:0      [点我收藏+]

标签:最大流 acm 二分

解题报告 之 HOJ2816 Power Line


Problem Description

While DUT is hosting this NECPC Contest, in order to control the expenditure, careful considerations should be given in many respects, such as the layout of the contest venue. When the contest venue is arranged, each computer requires power input. While the layout of computers and power-points are already fixed, some lines have to be purchased to link the computers with power-points. And, Raven finds out that it is cheaper to buy power lines of the same length than to buy lines of different lengths, so he would buy all the lines with the same length. If Raven wants to save money, would you help him?

Input Details

The first line of the input contains an integer T, which indicates the number of test cases.

For each test case, there are three positive integers in the first row, n, m, p (0 <= n, m <= 200,0 < p < 100). It means that there are n computers and m power-points. The power line costs ¥p per unit.

In the following n rows, i-th line has m positive integers indicating the distances between the i-th computer and all the power points. The distance is less than 10000.

In the last row, there are m positive integers, ci (0 < ci < 5,0 <= i < m), showing No.i power-point can provide power to ci computers in total.

Output Details

For each case, if the layout of computers and power lines are not reasonable, which means you cannot provide power to every computer, just output -1.

Otherwise, output the lowest total price for power lines.

Sample Input

1
2 2 1
1 3
2 2
1 1

Sample Output

4

Hint:

You many link the first computer with the first power-points, and link the second computer with the second power-points. This will cost 4(2*2). 



题目大意:有n台电脑,m个插线板。现在需要配置电源线,价格为p元/米。为了节约成本,现在决定所买的电源线都一样长。给出每天闹电脑离每个插线板的距离 以及 每个插线板能够容纳的数量,问你最少需要花多少钱?

分析:这个题给了电源线都一样长的条件,还不是明显的最大值最小。所以妥妥的用二分,然后这种分配问题用最大流解决,算是一个经典的搭配了。具体操作如下,二分最大的电源线长度mid,然后将超级源点与所有电脑连接,负载为1;每台电脑与距离它mid以内的插线板相连,负载为1;每个插线板与超级汇点相连,负载为它能容纳的数量。然后跑最大流看是否>=n,来决定二分的方向。如果最后low=INF-1,则说明没有解,输出-1。

上代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;

const int MAXN = 810;
const int MAXM = 90000;
const int INF = 0x3f3f3f3f;

struct Edge
{
	int from, to, cap, next, oricap;
};

Edge edge[MAXM];
int head[MAXN];
int cap[MAXN];
int dist[MAXN][MAXN];
int level[MAXN];
int src, des, cnt;

void addedge( int from, int to, int cap )
{
	edge[cnt].from = from;
	edge[cnt].to = to;
	edge[cnt].cap = cap;
	edge[cnt].oricap = cap;
	edge[cnt].next = head[from];
	head[from] = cnt++;

	swap( from, to );

	edge[cnt].from = from;
	edge[cnt].to = to;
	edge[cnt].cap = 0;
	edge[cnt].oricap = 0;
	edge[cnt].next = head[from];
	head[from] = cnt++;
}

int bfs( )
{
	memset( level, -1, sizeof level );
	queue<int> q;
	while (!q.empty( ))
		q.pop( );

	level[src] = 0;
	q.push( src );

	while (!q.empty( ))
	{
		int u = q.front( );
		q.pop( );

		for (int i = head[u]; i != -1; i = edge[i].next)
		{
			int v = edge[i].to;
			if (edge[i].cap > 0 && level[v] == -1)
			{
				level[v] = level[u] + 1;
				q.push( v );
			}
		}
	}
	return level[des] != -1;
}

int dfs( int u, int f )
{
	if (u == des)	return f;
	int tem;
	for (int i = head[u]; i != -1; i = edge[i].next)
	{
		int v = edge[i].to;
		if (edge[i].cap > 0 && level[v] == level[u] + 1)
		{
			tem = dfs( v, min( f, edge[i].cap ) );
			if (tem > 0)
			{
				edge[i].cap -= tem;
				edge[i ^ 1].cap += tem;
				return tem;
			}
		}
	}
	level[u] = -1;
	return 0;
}

int Dinic( )
{
	int ans = 0, tem;
	while (bfs( ))
	{
		while ((tem = dfs( src, INF )) > 0)
		{
			ans += tem;
		}
	}
	return ans;
}

int main( )
{
	int kase;
	cin >> kase;
	while (kase--)
	{
		int n, m, p;
		cin >> n >> m >> p;
		src = 0; des = 805;

		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= m; j++)
			{
				cin >> dist[i][j];
			}
		}
		for (int i = 1; i <= m; i++)
			cin >> cap[i];
		int low = 0, high = INF - 1;
		int ans = -1;
		while (low <= high)
		{
			int mid = (high + low) / 2;
			memset( head, -1, sizeof head );
			cnt = 0;

			for (int i = 1; i <= n; i++)
			{
				addedge( src, i, 1 );
			}
			for (int i = 1; i <= n; i++)
			{
				for (int j = 1; j <= m; j++)
				{
					if (dist[i][j] <= mid)
						addedge( i, j + 200, 1 );
				}
			}
			for (int i = 1; i <= m; i++)
			{
				addedge( i + 200, des, cap[i] );
			}

			if (Dinic() < n)	low = mid + 1;
			else
			{
				ans = mid;
				high = mid - 1;
			}
		}
		if (low >= INF - 1)
			cout << -1 << endl;
		else
			cout << ans*p*n << endl;
	}

	return 0;
}

肿么办肿么办我的项目怎么结题啊!!!

解题报告 之 HOJ2816 Power Line

标签:最大流 acm 二分

原文地址:http://blog.csdn.net/maxichu/article/details/45232711

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!