poj 1201(and)1716 (差分约束系统的建立和求解--其实也是spfa)

本文介绍了一种使用SPFA算法解决特定区间覆盖问题的方法。通过构建差分约束系统并利用SPFA算法找到从起点到终点的最长路径,解决了给定条件下集合C的最小元素数量问题。文章提供了详细的算法实现步骤及C++代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        这题好。

        题意:给n个区间中至少需要取Ci个数。求出满足n个条件的集合C的最少的元素个数.

转载结题报告:

        题目中的条件可以表示成S[bi+1]>=S[ai]+Ci//至少要Ci个。

       这与spfa中的松弛操作时很像的。因此可以看成一些点有D[v]>=D[u]+w(u,v)上式对任何u成立,所以v应该是里面最大的,若D[v]<D[u]+w(u,v)则D[v]=D[u]+w(u,v)于是。可以从ai和bi+1连一条线,它的长度是ci。

        这里只有这些条件还是不够的,还要加上两个使其满足整数性质条件1>=s[i+1]-s[i]>=0有了这么多条件,使其自然构成了一个差分约束系统。用spfa算法得到一个最长路,第一个到最后一个节点的最长路即是需要求的值。

      根据条件:1>=s[i+1]-s[i]>=0.在i和i+1建立权值为0,i和i-1建立权值为-1;

#include <iostream>
#include <queue>
#include <set>
#include <string>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;


const int INF=99999999;
struct node
{
   int v;
   int w;
};


int n;
vector<node>vv[50001];//存储有向和无向图的比较方便的方法
int dist[50001];


int MIN=500090;
int MAX=-1;
int vis[50003];


void spfa()//模型就是以MIN位原点的最长路
{
  memset(vis,0,sizeof(vis));
  queue<int>qu;
  vis[MIN]=1;
  dist[MIN]=0;
  qu.push(MIN);
  while(!qu.empty())
  {
      int top=qu.front();
      qu.pop();
      vis[top]=0;
      for(int i=0;i<vv[top].size();i++)
      {
          if(dist[vv[top][i].v]<dist[top]+vv[top][i].w)//松弛
          {
              dist[vv[top][i].v]=dist[top]+vv[top][i].w;
              if(!vis[vv[top][i].v])
              {
                      vis[vv[top][i].v]=1;
                      qu.push(vv[top][i].v);
              }
          }
      }
  }
}


int main()
{
    scanf("%d",&n);
    int u,v,c;
    node newone;


    for(int i=0;i<n;i++)
    {
      scanf("%d%d",&u,&v);
      v++;
      MIN=min(MIN,u);
      MAX=max(MAX,v);
      newone.v=v;
      newone.w=2;
      vv[u].push_back(newone);
    }


    for(int i=MIN;i<=MAX;i++)
    {
        node tmp;
        tmp.v=i+1;
        tmp.w=0;
        vv[i].push_back(tmp);


        tmp.v=i;
        tmp.w=-1;
        vv[i+1].push_back(tmp);
    }


    for(int i=MIN;i<=MAX;i++)
    {
        dist[i]=-INF;//求最长路嘛,就是初始化无穷小的
    }
    spfa();
    cout<<dist[MAX]<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值