CCF乔乔牛牛逛超市

这是一个最大权闭合子图问题。
之所以会有最大权闭合子图问题的主要原因是因为这个图中存在一部分点的权值是负数。

对最大权闭合子图的解释在这个链接最大权闭合子图
对这道题的解释在这个链接题目思路

经过测试,分数为100

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#include<cmath>
#include<queue>


typedef long long LL;
#define MAX1 20050
#define DEBUG
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;



struct edge {
	int to;
	LL  cap;
	int rev;
}Edges[MAX1];



struct Des {
	LL L, R, a, b, c;
}des[MAX1];

vector<edge>G[MAX1];
int level[MAX1];
int iter[MAX1];




void add_edge(int from,int to,LL cap)
{
	G[from].push_back({ to,cap,(int)G[to].size() });
	G[to].push_back({ from,0,(int)G[from].size() - 1 });
}
void BFS(int s)
{
	memset(level, -1, sizeof(level));
	queue<int>que;
	level[s] = 0;
	que.push(s);
	while (!que.empty())
	{
		int v = que.front();
		que.pop();
		for (int i = 0; i < G[v].size(); i++)
		{
			edge& e = G[v][i];
			if (e.cap > 0 && level[e.to] < 0)
			{
				level[e.to] = level[v] + 1;
				que.push(e.to);
			}
		}

	}

}



int DFS(int v, int t, LL f)
{
	if (v == t)return f;
	for (int &i = iter[v]; i < G[v].size(); i++)
	{//iter实际上是替代了used数组的作用
		edge& e = G[v][i];
		
		if  (e.cap > 0&&level[v]<level[e.to])
		{
			int d = DFS(e.to, t, min(f, e.cap));
			if (d > 0)
			{
				e.cap -= d;
				G[e.to][e.rev].cap += d;
				return d;
			}
		}
	}
	return 0;
}

LL twofun(int x,int i)
{
	return  des[i].a * x * x + des[i].b * x + des[i].c;
}
//在边界上取值
LL Boundary(int i)
{
	LL Left = twofun(des[i].L, i);
	LL Right = twofun(des[i].R, i);
	return max(Left, Right);
}
LL calcu(int i)
{
	int l = des[i].L + 1;
	int r = des[i].R - 1;
	//中间轴
	if (l > r)
		return 0;
	if (des[i].a > 0)
	{
		return max(twofun(l, i), twofun(r, i));
	}
	if (des[i].a < 0)
	{
		double center = -des[i].b / 2.0 / des[i].a;
		
		if (center >r)
			return twofun(r, i);
		else if (center <l)
		{
			return twofun(l, i);
		}
		else {
			return max( twofun(floor(center), i),twofun(ceil(center),i));
		}

	}
	if (des[i].b > 0)
		return twofun(r, i);
	else
	{
		return twofun(l, i);
	}

}
LL max_flow(int s, int t)
{
	LL flow = 0;
	while (true)
	{
	

		BFS(s);
		if (level[t] < 0)return flow;
		memset(iter, 0, sizeof(iter));
		int f;
		while ((f=DFS(s,t,INF))>0)
		{
			flow += f;
			
		}
			
	}
	return 0;
}

int main()
{
#ifdef DEBUG
	freopen("sb.txt", "r", stdin);
#endif // DEBUG
	

	int countA, countB;
	cin >> countA >> countB;
	LL possum = 0;
	int MAX = 2 * countA + 1;//汇点以后最好就按照这个方法来计算
	for (int i = 1; i <= countA; i++)
	{
		scanf("%lld %lld %lld %lld %lld", &des[i].L, &des[i].R, &des[i].a, &des[i].b, &des[i].c);
		
		
		LL v1 = calcu(i);//第一类点
		LL v2 = Boundary(i)-v1;

		possum += max((LL)0, v1) + max((LL)0, v2);
		
		
		add_edge(i+countA,i,INF);

		if (v1 > 0)
		{
			add_edge(0,i,v1);
		}
		else if(v1<0)
		{
			add_edge(i, MAX, -v1);
		}
		if (v2 > 0)
		{
			add_edge(0,i+countA,v2);
		}
		else if(v2<0)
		{
			add_edge(i+countA,MAX,-v2);
		}	
	}
	//int possum = 0;
	for (int i = 0; i < countB; i++)
	{
		int pointA, pointB, z;
		scanf("%d %d %d", &z ,&pointA, &pointB);
		if (z == 1)
		{
			add_edge(pointB, pointA, INF);
		}
		else
		{
			add_edge(pointB + countA, pointA, INF);
		}
	}
	
	cout <<possum- max_flow(0, MAX);
	
	return 0;
}


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值