poj1201(差分约束 + spfa)

         题目链接:http://poj.org/problem?id=1201

         题目意思:有n个区间[ai,bi],找一最短序列,要求该序列中至少有ci个数字在区间[ai,bi]上。        

        思路:差分约束系统,感兴趣的同学可以点击链接看看,以dis[i]表示该序列出现在区间[0,i]内的数字个数,minnum与maxnum分别表示n个区间并集的下界和上界,则该序列的长度为dis[maxnum]-dis[minnum],根据差分约束要求,该题有一下两点约束条件。

                1、dis[bi+1]-dis[ai]>=ci;(题目要求)

                2、0<=dis[i+1]-dis[i]<=1;(隐藏条件)

代码:

#include<stdio.h>
#include<string.h>
#define INF 100000000;
struct node{
	int v;
	int w;
	int next;
}edge[150015];
int head[50005];
int dis[50005];
int visted[50005];
int quene[1000000];//队列数组一定要足够大,开始因为这wrong了两次
int qhead,qtail;
int ans,maxnum,minnum;
int n,m,a,b,c;
int max(int x,int y)
{
	return x>y ? x : y;
}
int min(int x,int y)
{
	return x<y ? x : y;
}
void addedge(int a,int b,int c)//数组模拟邻接表存储图
{
    edge[m].v=b;
	edge[m].w=c;
	edge[m].next=head[a];
	head[a]=m;
	m++;
}

void Inq(int V)
{
	quene[++qtail]=V;
}
void Outq()
{
	qhead++;
}
int emptyq()
{
	if(qhead>qtail)
		return 1;
	else return 0;
}
int getHead()
{
    return quene[qhead];
}

int spfa()//spfa+栈
{
     int i;
	 int temp;
	 for(i=minnum;i<=maxnum;i++)
		 dis[i]=-INF;
	 memset(visted,0,sizeof(visted));
	 qhead=0;
	 qtail=-1;
	 Inq(minnum);
	 dis[minnum]=0;
	 visted[minnum]=1;
	 while(!emptyq())
	 {
          temp=getHead();
		  Outq();
		  visted[temp]=0;
		  for(i=head[temp];i!=-1;i=edge[i].next)
		  {
			  if(dis[edge[i].v]<dis[temp]+edge[i].w)
			  {
					dis[edge[i].v] = dis[temp]+edge[i].w;
					if(!visted[edge[i].v])
					{
						Inq(edge[i].v);
						visted[edge[i].v]=1;
					}
			  }
		  }
	 }
   return dis[maxnum]-dis[minnum];	 
}

int main()
{
	int i;
	while(scanf("%d",&n)!=EOF)
	{
		m=0;
		maxnum=-INF;
		minnum=INF;
	    memset(head,-1,sizeof(head));
		while(n--)
		{
            scanf("%d%d%d",&a,&b,&c);
			maxnum=max(maxnum,b+1);//获得所有区间的上下界
			minnum=min(minnum,a);
			 addedge(a,b+1,c);//约束条件dis[b+1]-dis[a]>=c
			
		}
		for(i=minnum;i<maxnum;i++)
		{
			addedge(i,i+1,0);//约束条件dis[i+1]-dis[i]>=0;
			addedge(i+1,i,-1);//约束条件dis[i+1]-dis[i]<=1;
		}
		ans=spfa();
		printf("%d\n",ans);
	}
	return 0;
}


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值