题目链接: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;
}