这题依然 SPFA + 栈 过!
不同的是,这题有隐含条件,而且所求也大不一样。
由于这是对区间操作,求至少包含区间[ai, bi]中ci个点的最小集合。可以用集合元素个数来定义变量,即num[bi] - num[ai] >= ci, 但有个隐含条件就是,每个元素都是整点,取得话,最多为一,最少为0, 即 num[i+1] - num[i] <= 1, num[i+1] - num[i] >= 0, 将这些条件再转换成最短路里的边和权,就可以做了。
这里求得是至少,也就是最小值,即 num[maxn] - num[0] >= ans, 我们要转化成 <= 号,也就是 num[0] - num[maxn] <= -ans, 这样就行了,赋初值时,令dis[maxn] = 0,求得就是每个点到maxn的距离了,输出结果就是dis[0]加个负号。
代码
#include
<
stdio.h
>
#include < stdlib.h >
#define INF 0xfffffff
#define NN 50004
#define MM 150004
int edNum, maxn;
int mark[NN];
int root[NN];
int dis[NN];
int next[MM];
int stack[NN];
struct node{
int e, v;
}edge[MM];
void Init(){
int i;
for (i = 0 ; i < NN; i ++ ){
mark[i] = 0 ;
root[i] = - 1 ;
dis[i] = INF;
}
}
void add( int a, int b, int c){
edge[edNum].e = b;
edge[edNum].v = c;
next[edNum] = root[a];
root[a] = edNum ++ ;
}
void Spfa()
{
int i, cur, nxt, tmp, top = 0 ;
for (i = 0 ; i <= maxn; i ++ ){
if (root[i] != - 1 ){
stack[ ++ top] = i;
mark[i] = 1 ;
}
}
// 这里需要注意,要将终点置零,求的就是别的点到终点maxn的距离
dis[maxn] = 0 ;
while (top){
cur = stack[top -- ];
mark[cur] = 0 ;
tmp = root[cur];
while (tmp != - 1 ){
nxt = edge[tmp].e;
if (dis[nxt] > dis[cur] + edge[tmp].v){
dis[nxt] = dis[cur] + edge[tmp].v;
if ( ! mark[nxt]){
mark[nxt] = 1 ;
stack[ ++ top] = nxt;
}
}
tmp = next[tmp];
}
}
}
int main()
{
int n, i, a, b, c;
scanf( " %d " , & n);
maxn = 0 ;
edNum = 0 ;
Init();
for (i = 1 ; i <= n; i ++ ){
scanf( " %d%d%d " , & a, & b, & c);
add(b + 1 , a, - c);
if (b + 1 > maxn){
maxn = b + 1 ;
}
}
for (i = 0 ; i <= maxn; i ++ ){
add(i + 1 , i, 0 );
add(i, i + 1 , 1 );
}
Spfa();
// 输出的时候也要注意,是起点到终点的距离的负值
printf( " %d\n " , - dis[ 0 ]);
// system("pause");
return 0 ;
}
#include < stdlib.h >
#define INF 0xfffffff
#define NN 50004
#define MM 150004
int edNum, maxn;
int mark[NN];
int root[NN];
int dis[NN];
int next[MM];
int stack[NN];
struct node{
int e, v;
}edge[MM];
void Init(){
int i;
for (i = 0 ; i < NN; i ++ ){
mark[i] = 0 ;
root[i] = - 1 ;
dis[i] = INF;
}
}
void add( int a, int b, int c){
edge[edNum].e = b;
edge[edNum].v = c;
next[edNum] = root[a];
root[a] = edNum ++ ;
}
void Spfa()
{
int i, cur, nxt, tmp, top = 0 ;
for (i = 0 ; i <= maxn; i ++ ){
if (root[i] != - 1 ){
stack[ ++ top] = i;
mark[i] = 1 ;
}
}
// 这里需要注意,要将终点置零,求的就是别的点到终点maxn的距离
dis[maxn] = 0 ;
while (top){
cur = stack[top -- ];
mark[cur] = 0 ;
tmp = root[cur];
while (tmp != - 1 ){
nxt = edge[tmp].e;
if (dis[nxt] > dis[cur] + edge[tmp].v){
dis[nxt] = dis[cur] + edge[tmp].v;
if ( ! mark[nxt]){
mark[nxt] = 1 ;
stack[ ++ top] = nxt;
}
}
tmp = next[tmp];
}
}
}
int main()
{
int n, i, a, b, c;
scanf( " %d " , & n);
maxn = 0 ;
edNum = 0 ;
Init();
for (i = 1 ; i <= n; i ++ ){
scanf( " %d%d%d " , & a, & b, & c);
add(b + 1 , a, - c);
if (b + 1 > maxn){
maxn = b + 1 ;
}
}
for (i = 0 ; i <= maxn; i ++ ){
add(i + 1 , i, 0 );
add(i, i + 1 , 1 );
}
Spfa();
// 输出的时候也要注意,是起点到终点的距离的负值
printf( " %d\n " , - dis[ 0 ]);
// system("pause");
return 0 ;
}