poj1201

题意:给定一些区间和每个区间内的元素数量(选一些互不相同的整数作为区间内的元素,每个整数只至多选1次),问最少有多少个元素(所有元素不能重复)。

分析:这题是用spfa做差分约束。不能向bellman一样。还是把差分约束理解为求最长路比较直观。

对于dist[a]-dist[b]>=c,我们可以看作dist[a]>=dist[b]+c,所以我们如果初始化为负无穷,起点初始化为0,并让所有的不等式都满足,那么就是在求一个最长路。

首先用数组sum[i]表示小于等于i的元素有多少个。这样区间[a+1,b]的元素个数要求c,可以表示为sum[b]-sum[a]>=c。还要注意每个元素要么选要么不选,其数量只能是0或1。因此,0<=sum[i]-sum[i-1]<=1

View Code
#include < iostream >
#include
< cstdio >
#include
< cstdlib >
#include
< cstring >
using namespace std;

#define maxn 50005
#define INF 0x3f3f3f3f

int pnt[maxn * 3 ], cost[maxn * 3 ], nxt[maxn * 3 ];
int e, head[maxn];
int dist[maxn];
bool vis[maxn];
int n, mmin, mmax;

int relax( int u, int v, int c)
{
if (dist[v] < dist[u] + c)
{
dist[v]
= dist[u] + c;
return 1 ;
}
return 0 ;
}

inline
void addedge( int u, int v, int c)
{
pnt[e]
= v;
cost[e]
= c;
nxt[e]
= head[u];
head[u]
= e ++ ;
}

int SPFA( int src, int n)
{
int i;
for (i = src; i <= n; i ++ )
{
vis[i]
= 0 ;
dist[i]
= - INF;
}
dist[src]
= 0 ;
int Q[maxn * 3 ], top = 1 ;
Q[
0 ] = src;
vis[src]
= true ;
while (top)
{
int u, v;
u
= Q[ -- top];
vis[u]
= false ;
for (i = head[u]; i != - 1 ; i = nxt[i])
{
v
= pnt[i];
if ( 1 == relax(u, v, cost[i]) && ! vis[v])
{
Q[top
++ ] = v;
vis[v]
= true ;
}
}
}
return dist[n];
}

void input()
{
mmax
= 0 ;
mmin
= INF;
for ( int i = 0 ; i < n; i ++ )
{
int a, b, c;
scanf(
" %d%d%d " , & a, & b, & c);
a
++ ;
b
++ ;
if (mmax < b)
mmax
= b;
if (mmin > a)
mmin
= a;
addedge(a
- 1 , b, c);
}
for ( int i = mmin; i <= mmax; i ++ )
{
addedge(i, i
- 1 , - 1 );
addedge(i
- 1 , i, 0 );
}
}

int main()
{
// freopen("t.txt", "r", stdin);
scanf( " %d " , & n);
e
= 0 ;
memset(head,
- 1 , sizeof (head));
input();
printf(
" %d\n " , SPFA(mmin - 1 , mmax));
return 0 ;
}

你可能感兴趣的:(poj)