想看更多的解题报告: 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; }