这题好。
题意:给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;
}