POJ1201 Intervals [差分约束系统 SPFA]

题意:

给定m个区间,且在每个区间内必须至少取有w个数,如果取数可以使总的区间取的数个数最少。

思路:

差分约束系统 最短路求最优解
先是根据题目条件构造一个差分约束系统。
例如题目给的条件 u v w,可以转化为d[u]-d[v-1]>=w这个约束条件。
所以依次可以得到
d[7]-d[2]>=3;
d[10]-d[7]>=3;
d[8]-d[5]>=1;
d[3]-d[0]>=1;
d[11]-d[9]>=1;
这五个约束方程。
还有两个重要的隐含方程:
因为:0<=d[i]-[i-1]<=1;
所以:
d[i]-d[i-1]>=0;
d[i-1]-d[i]>=-1;
目标方程:y=d[11]-d[0]>=?


以上就是差分约分系统。
接下来则是最短路SPFA的求解方法:


d[i]表示图上的第i个节点。
初始化d[i]=0;0<=i<=n;
d[i]-d[j]>=w;表示图上从点i到点j的权值为w的边。
设置一个超级源点s,d[s]=0;d[s]-d[i]>=0;0<=i<=n;s可以取值为n+1;
然后用SPFA算法处理求"最长路"。
即松弛方法改为:
if(d[i]<d[j]+w)
d[i]=d[j]+w;


最后d[n]的值即是最优解。


#include<iostream>
#include<vector>
#include<string>
#include<queue>
#include<algorithm>
#define llong long long
#define Min(a,b) (a<b?a:b)
#define Max(a,b) (a>b?a:b)
#define Abs(a) ((a)>0?(a):-(a))
#define Mod(a,b) (((a)-1+(b))%(b)+1)
using namespace std;
const int N=50005;
const int M=200005;
const int inf=1e10;
int n,m;
struct 
{
	int v,next,w;
}edge[M];
int edgehead[N];
int d[N];
int vis[N];
int k;
void addedge(int u,int v,int w)
{
	edge[k].w=w;
	edge[k].v=v;
	edge[k].next=edgehead[u];
	edgehead[u]=k++;
}
void solve()
{
	queue<int> que;
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++)
		d[i]=-inf;
	d[0]=0;
	vis[0]=true;
	que.push(0);
	while(!que.empty())
	{
		int now=que.front();
		que.pop();
		vis[now]=false;
		for(int i=edgehead[now];i;i=edge[i].next)
		{
			int v=edge[i].v;
			int w=edge[i].w;
			if(d[v]<d[now]+w)
			{
				d[v]=d[now]+w;
				if(!vis[v])
				{
					vis[v]=true;
					que.push(v);
				}
			}
		}
	}
	printf("%d\n",d[n]);
}
int main()
{
	int u,v,w;
	n=0;
	scanf("%d",&m);
	k=1;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&u,&v,&w);
		addedge(u,v+1,w);
		n=max(n,v+1);
	}
	for(int i=0;i<=n;i++)
	{
		addedge(i,i+1,0);
		addedge(i+1,i,-1);
	}
	solve();
	return 0;
}

第一道差分约束题。虽然感觉并不是很难,但是构图方法还是挺巧妙的有时候不容易想到。

你可能感兴趣的:(POJ1201 Intervals [差分约束系统 SPFA])