Codevs 线段覆盖1&2&3&4&5

对于线段覆盖1、3,贪心,每次选取末端点靠前的,O(n)扫一遍即可(话说这个题似乎排序最占时间)。(当然DP也可以)
#include
#include
#define maxn 1000000+5
using namespace std;
struct line{
	int b,e;
	friend bool operator < (line x,line y){
		if(x.e!=y.e)return x.ey.b;
	}
}l[maxn];
int main(){
	ios::sync_with_stdio(false);
	int n,i,j,k,x,y;cin>>n;
	for(i=1;i<=n;i++){
		cin>>x>>y;
		if(x>y)swap(x,y);
		l[i].b=x;l[i].e=y;
	}
	sort(l+1,l+n+1);
	int pos=-1,cnt=0;i=1;
	while(i<=n){
		if(l[i].b>=pos){
			cnt++;
			pos=l[i].e;
		}
		i++;
	}
	cout<

 但是对于线段有权值的情况,可以证明贪心是行不通的,这时候就必须DP

我的做法是:设dp[I]表示到第i条线段可获得的最大价值,容易得到这样的状态转移方程:

dp[I]=max(dp[I-1],dp[j]+line[i].c),j表示距离i最近的与i没有交集的线段。

对于查找线段j,朴素的做法就是从i开始向前枚举,然而这样只能通过线段覆盖2,对于4会TLE两个点,5会TLE7个点。

仔细分析线段性质,可以发现由于我们对线段进行了排序,所以线段的末端点对于线段的编号是具有单调性的,所以可以使用二分查找第一个满足此性质的线段。

#include
#include
#define int long long
#define maxn 1000000+5
using namespace std;
struct line{
	int b,e,c;//begin,end,cost
	friend bool operator < (line x,line y){
		if(x.e!=y.e)return x.e>1;
			if(l[mid].e>l[i].b){
				ri=mid-1;
			}
			else if(l[mid].e<=l[i].b){
				lf=mid+1;
			}
		}
		if(l[lf].e<=l[i].b)return lf;
		return lf-1;
	}
	else{//朴素查找
		int p=i;
		while(l[p].e>l[i].b)p--;
		return p;
	}
}
#undef int
int main(){
	ios::sync_with_stdio(false);
	int n,i,j,k;cin>>n;
	for(i=1;i<=n;i++){
		cin>>x>>y>>z;
		l[i].b=x;l[i].e=y;l[i].c=z;
	}
	sort(l+1,l+n+1);
	l[0].b=l[0].e=l[0].c=-1;
	for(int i=1;i<=n;i++)
		dp[i]=max(dp[i-1],dp[bsearch(i,0)]+l[i].c);
	cout<

然而还有另一种DP思路,(%ZY),设dp[I]表示在坐标I的最大价值,可行的一种状态转移方程为:

f[line[I].e]=max(f[line[I].e],f[line[I].b]+line[I].c);

转移时枚举line[I].e而不是每个坐标

在每次循环时,拿f[line[I].e]来更新从f[Iine[I].e+1]到f[Iine[I+1].e]中的所有点,这样可以实现在转移时选或不选这条线段的操作。

对于线段覆盖4、5,数据范围过大,需要离散化。

#include
#include
#include
using namespace std;
struct segment
{
	long long b,e,c;
}a[1000005];
struct mes
{
	long long pos,rank;
}t;
long long n,i,j,pre,p,f[1000005];
struct cmp2
{
	bool operator()(mes x,mes y)
	{
		return x.pos>=y.pos;
	}
};
priority_queue,cmp2> q;
bool cmp(segment x,segment y)
{
	return x.e>n;
	for(i=1;i<=n;i++)
	{
		cin>>a[i].b>>a[i].e>>a[i].c;
		q.push((mes){a[i].b,(i<<1)-1});//奇数节点为begin
		q.push((mes){a[i].e,i<<1});//偶数节点为end
	}
	pre=q.top().pos;
	for(i=1;i<=n+n;i++)
	{//离散化
		t=q.top();
		q.pop();
		if(t.pos!=pre)//如果两个点的坐标不相同
		{
			++p;
			pre=t.pos;
		}
		if((t.rank&1)==1) a[(t.rank+1)>>1].b=p;
		else a[(t.rank)>>1].e=p;
	}
	sort(a+1,a+n+1,cmp);
	for(i=1;i


你可能感兴趣的:(DP,贪心)