模板_poj1201Intervals_差分约束系统解决(类区间问题)

poj1201题目链接

题意:

第一行输入n,下面输入n个限制条件,条件的格式为 ai bi ci,  0<=ai<=bi<=50000,1<=ci<=bi-ai+1.表示在区间[ai,bi]上至少选ci个点,使被选出的点的个数最少而且满足所有的限制条件,输出这个最小值。


差分约数系统的含义,其实就是如果有n个变量在m个形如aj-ai>=bk(类似于求最长路径)条件下,求解的此不等式的方法。
 而这种不等式的解法其实就是转化为图论的最小路的算法求解的。我们将上面的不等式边形后得到aj>=ai+bk正好就可以看做是从ai到aj权值是bk的一条路径最短的边。这样一来,只要依照题目的条件写出一系列这样的不等式,也就是相当于按照题意增加了一些合法的边,也就完全转化为了最短路的算法。转化详解
但要注意的是,由于查分约束系统里常常会有负权边,所以为了避免负权回路,往往用Bellman-Ford或是SPFA求解(存在负权回路则最短路不存在)。

差分约束系统讲解



看时间:第一次我用的是数组实现邻接表,第二个我我用的是vector动态数组。在做poj3159题的时候用vector就直接超时了。。找了半天错也没找出来,更好笑的事那个用的还是栈,这个用栈直接就超时了。。。我到现在还是不解为甚用vector会超时!觉得没差啊~~~想了下这两道题的共同点就是数据量大。边多点多。就是想不通为什么在时间上的差异这么大,让我研究一下吧(知道的可以给我留下言啊,一起讨论下)。。

Sample Input

5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1

Sample Output

6

#include<stdio.h>
#include<string.h> 
#include<vector>
#include<queue>

#define inf 1<<28
using namespace std;

#define MIN(a,b) a<b?a:b
#define MAX(a,b) a>b?a:b

struct node
{
	int u,v,w,next;
}e[50005*3];

int vis[50005];
int dis[50005];
int head[50005];
int num,maxi,mini;

void add_edge(int u,int v,int w)
{
	e[num].v=v;
	e[num].w=w;
    e[num].next=head[u];
	head[u]=num++;	
}
void SPFA()
{
	memset(vis,0,sizeof(vis));
	int v,i,w,u;
	queue<int>Q;
	Q.push(mini);
	vis[mini]=1;
	dis[mini]=0;
	
	while(!Q.empty())
	{
		u=Q.front();
		Q.pop();
		vis[u]=0;
		
		for(i=head[u];i!=-1;i=e[i].next)
		{
			v=e[i].v;
			w=e[i].w;
			
			if(dis[v]<dis[u]+w)
			{
				dis[v]=dis[u]+w;
				
				if(!vis[v])
				{
					vis[v]=1;
					Q.push(v);
				}
			}
			  
		}
	}
}
int main()
{
	int i,a,b,c,n;
	
	while(~scanf("%d",&n))
	{
		memset(dis,-1,sizeof(dis));
	    memset(head,-1,sizeof(head));
		num=0;
		mini=inf;
		maxi=-inf;
		
		for(i=0;i<n;i++)
		{
			scanf("%d%d%d",&a,&b,&c);
			add_edge(a,b+1,c);
			mini=MIN(mini,a);
			maxi=MAX(maxi,b+1);
		}
		for(i=mini;i<maxi;i++)
		{
			add_edge(i,i+1,0);
			add_edge(i+1,i,-1);
		}
		SPFA();
		printf("%d\n",dis[maxi]);
	}
	
	
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值