题意:给你一组区间a和b ,你在这里最少选择c个点,问你最少选择多少个点可以满足条件。
思路:在刚开始着手这道题的时候是不是一点思路都没有,嗯,在仔细想想你会发现你还是没思路。。。对,正解思路是差分约束,我们先假设dis[i]表示的是从0到i中可以选择的点,那么从区间a到b至少选择c个点转化一下就是
dis[b+1] - dis[a] >= c
之后我们换一下位置就是 dis[b+1] >= c + dis[a],对这就是最短路的松弛操作嘛,但是仅仅这样建边我们我们是到达不了终点的。。还有一些隐性的条件,因为我们挑选的是区间所以就有 0 <=dis[i] - dis[i-1] <=1 所以这三个条件就构成了我们的这道题
dis[b+1] - dis[a] >= c
dis[i] - dis[i-1] >=0
dis[i-1] - dis[i] >= -1
上代码把:
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
#define INF 1000000007
const int maxn = 50000+10;
int Min , Max,cnt;
struct node
{
int to,nex,v;
}edg[maxn*4];
int dis[maxn],vis[maxn],head[maxn];
void init()
{
memset(head,-1,sizeof(head));
memset(edg,0,sizeof(edg));
cnt = 0 ;
}
void add(int u,int v,int w)
{
edg[cnt].to = v;
edg[cnt].nex = head[u];
edg[cnt].v = w;
head[u] = cnt++;
}
void SPFA()
{
for(int i = 0 ; i <= maxn ; i++)
{
dis[i] = -INF;
vis[i] = 0;
}
dis[Min] = 0;
queue<int>que;
que.push(Min);
while(!que.empty())
{
int u = que.front();
que.pop();
vis[u] = 0;
for(int i = head[u] ; i!=-1 ; i = edg[i].nex)
{
int v = edg[i].to;
int w = edg[i].v;
if(dis[v] < dis[u] + w)
{
dis[v] = dis[u] + w;
if(!vis[v])
{
vis[v] = 1;
que.push(v);
}
}
}
}
}
int main()
{
int n;
scanf("%d",&n);
int x,y,c;
Min = INF,Max = -INF;
init();
for(int i = 0 ; i < n ;i++)
{
//cin>>x>>y>>c;
scanf("%d%d%d",&x,&y,&c);
y++;
add(x,y,c);
Min = min(x,Min);//Min就是我们的源点
Max = max(y,Max);//Max就是我们终点
}
for(int i = Min ; i < Max ; i ++)
{
add(i+1,i,-1);//这里可能会出现-1的情况,所以我们让i都加了1
add(i,i+1,0);
}
// puts("-------");
/* for(int i = Min ;i < Max ; i ++)
{
for(int j = head[i] ; j!=-1; j = edg[j].nex)
{
printf("%d %d %d\n",i,edg[j].to,edg[j].v);
}
}*/
SPFA();
printf("%d\n",dis[Max]);
}