bzoj2034[2009国家集训队]最大收益

我们看完题目,大概都会有点想法,我们可以不断地贪心插入这个任务

实际上就是,我们把这些任务和对面的时间点看成一个二分图,于是我们可以思考二分图匹配,并用二分来查找时间点,类似匈牙利的思想把任务往后挤,挤不动就不插入

最开始的时候并没有看FQW的论文,然后稀里糊涂的写了一段又臭又长的代码,WA了。

FQW的实现还是比较简单的,而且那篇论文里面几乎把各种优化统统列出来了。

总体复杂度(N2),记得ans要是long long的,不然就会像我一样找了好久找不到措

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define LL long long
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
inline LL read()
{
	LL d=0,f=1;char s=getchar();
	while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
	while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
	return d*f;
}
#define N 5005
#define inf 1000000007
struct dian
{
	int be,en,v;
}d[N];
int f[N],b[N];
//bool v[N];
int n;
LL ans=0;

bool timecom(dian a,dian b)
{
	if (a.be==b.be) return a.en<b.en;
	else return a.be<b.be;
}

bool vcom(dian a,dian b)
{
	return a.v>b.v;
}
	
void lishan()
{
	sort(d+1,d+n+1,timecom);
	int t=0;
	fo(i,1,n)
	{
		t=max(t+1,d[i].be);
		b[i]=t;
	}
	b[n+1]=inf;
}

int erfen(int k,int l,int r)
{
//	cout<<d[k].be<<' '<<d[k].en<<' '<<l<<' '<<r<<' '<<b[l]<<' '<<b[r]<<' '<<endl;
	int mid=(l+r)>>1;
	if(d[k].be<=b[mid]&&b[mid]<=d[k].en)
	{
		while(d[k].be<=b[mid]) mid--;
		return mid+1;
	}
	if(d[k].be<=b[mid]) return erfen(k,l,mid-1);
	if(b[mid]<=d[k].en) return erfen(k,mid+1,r);
}

bool match(int k,int x)
{
	if(d[k].en<b[x])return 0;
	if(f[x]==0)
	{
		f[x]=k;
		return 1;
	}
	if(d[k].en>d[f[x]].en) return match(k,x+1);
	else 
	{
		if(match(f[x],x+1))
		{
			f[x]=k;
			return 1;
		}
	}
	return 0;
}

void work()
{
	sort(d+1,d+n+1,vcom);
	fo(i,1,n)
	{
		int j=erfen(i,1,n);
//		cout<<i<<' '<<j<<' '<<n<<endl;
		if(match(i,j))ans+=d[i].v;
//		cout<<ans<<' '<<d[i].v<<endl;
	}
}

int main()
{
	n=read();
	fo(i,1,n)
	{
		d[i].be=read();
		d[i].en=read();
		d[i].v=read();
	}
	lishan();
	work();
	cout<<ans<<endl;
	return 0;
}


你可能感兴趣的:(二分图匹配)