poj1752 - Advertisement

133 篇文章 0 订阅

                                  想看更多的解题报告: http://blog.csdn.net/wangjian8006/article/details/7870410
                                  转载请注明出处:http://blog.csdn.net/wangjian8006

题目大意:有n个人在一条路上跑步,广告商准备在这条路上设置广告牌,假设这条路上每一个点有一个广告牌
现在已知这n个人从Ai开始跑,到Bi结束,那么他可以看到max(Ai,Bi)-min(Ai,Bi)-1的广告牌数,现在广告商
需要每个人都要看到k个广告牌,这样,n个人过去了,问总的广告牌数和哪些广告牌是需要留下的

 

解题思路:差分约束:
从题目意思可以得到以下这些约束:
设a=max(Ai,Bi);
b=min(Ai,Bi)-1;
设c=a-b;
如果a-b>=k
那么得到一个约束a-b<=k
得到一条有向边<b,a>==k

如果a-b<k
则这个人只能看到a-b的广告牌
所以得到第二个约束a-b=c
变换一下就是
a-b<=c
a-b>=c---->b-a<=-c
得到两条边:
<b,a>===c
<a,b>===-c
当然还有一个大的约束条件是:
对于任意一点有0<=d[i+1]-d[i]<=1
即相邻两点的广告牌大于等于0小于等于1

  最后输出哪个广告牌存在时,得到d[i]-d[i-1]==1,即i-1到i有一块广告牌输出i
  总的广告牌数存在在d[end]

 

 

/*
Memory 956K
Time  500MS 
*/
#include <iostream>
#include <queue>
using namespace std;
#define MAXV 20000
#define INF 0xfffffff
#define min(a,b) (a>b?b:a)
#define max(a,b) (a<b?b:a)

typedef struct{
	int t,w,next;
}Edge;

Edge edge[8*MAXV];
int k,n;
int d[2*MAXV];
bool vis[2*MAXV];
int headlist[2*MAXV],edge_sum;
int start,end;

void swap(int &a,int &b){
	int tmp;
	tmp=a;a=b;b=tmp;
}

void addedge(int s,int t,int w){
	edge[edge_sum].t=t;
	edge[edge_sum].w=w;
	edge[edge_sum].next=headlist[s];
	headlist[s]=edge_sum++;
}

void spfa(){
	int i,v,t;
	queue <int>q;
	for(i=start;i<=end;i++){
		d[i]=-INF;
		vis[i]=0;
	}
	
	d[start]=0;
	vis[start]=1;
	q.push(start);
	while(!q.empty()){
		v=q.front();q.pop();
		vis[v]=0;
		
		for(i=headlist[v];i!=-1;i=edge[i].next){
			t=edge[i].t;
			if(d[v]+edge[i].w>d[t]){
				d[t]=d[v]+edge[i].w;
				if(!vis[t]){
					q.push(t);
					vis[t]=1;
				}
			}
		}
	}
}

int main(){
	int i,a,b,c;
	while(~scanf("%d%d",&k,&n)){
		edge_sum=0;start=INF;end=-1;
		memset(headlist,-1,sizeof(headlist));
		for(i=0;i<n;i++){
			scanf("%d%d",&a,&b);
			if(a>b) swap(a,b);
			a+=MAXV-1;
			b+=MAXV;
			start=min(start,a);
			end=max(end,b);
			c=b-a;
			if(c<k){
				addedge(a,b,c);
				addedge(b,a,-c);
			}else
				addedge(a,b,k);
		}
		
		for(i=start;i<=end;i++){		//相邻两点的约束条件
			addedge(i,i+1,0);
			addedge(i+1,i,-1);
		}
		
		spfa();
		
		printf("%d\n",d[end]);
		for(i=start;i<=end;i++){
			if(d[i]-d[i-1]==1)
				printf("%d\n",i-MAXV);
		}
	}
	return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值