本蒟蒻最近在复习图论,听机房里的大佬说这道题是一道差分约束裸题,就跑过来做了这道题。
简单介绍一下差分约束系统:差分约束系统就是给出n个变量 ,在m个形如 的不等式的约束下,求解所有满足这些不等式的解。
而查分约束系统可以通过图论解决。我们可以把每一个变量看做一个节点,而每个约束条件 可以视为 节点到 节点连了一条权值为的有向边。
在这个图中,节点到节点 的最短路为 的最大值,因为对于单源最短路径满足的三角不等式 ,在本图中为 ,变形可得 ,即节点 到节点 的最短路为 的最大值。
再看这道题,要在区间 [,] 中至少取任意互不相同的 个整数。我们不妨设p[k]为0到k之间选几个整数。由题意易得,,而题意中又有一些隐藏条件:
我们还需要建立一个根节点,与所有节点相连且边权为0,这样就可以以根节点为出发点跑一个最短/长路了。
得到这些条件后,就可以建一个图,然后跑一遍从根节点出发的最长路(因为要求最小值),再输出就可以了。
#include<bits/stdc++.h>
using namespace std;
int tot=0,dis[500003];
struct node{
int v,k;
};
vector<node>head[500003];//邻接表
inline int read(){
int s=0,g=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
g=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=(s<<3)+(s<<1)+(ch^48);
ch=getchar();
}
return s*g;
}
int max(int a,int b){
if(a>b)
return a;
return b;
}
void spfa(int start){//spfa求最长路
bool vis[500003];
queue<int> que;
que.push(start);
for(int i=0;i<=tot;i++){
dis[i]=-0x7fffffff;
vis[i]=false;
}
vis[start]=true;
dis[start]=0;
while(!que.empty()){
int num=que.front();
que.pop();
vis[num]=false;
for(int i=0;i<head[num].size();i++){
if(dis[head[num][i].v]<dis[num]+head[num][i].k){
dis[head[num][i].v]=dis[num]+head[num][i].k;
if(!vis[head[num][i].v]){
que.push(head[num][i].v);
vis[head[num][i].v]=true;
}
}
}
}
}
int main(){
int n,a,b,c,t;
node p;
t=read();
while(t){
n=read();
for(int i=0;i<=50002;i++){
vector<node>().swap(head[i]);
}//清空向量
tot=0;
for(int i=0;i<n;i++){
a=read(),b=read(),c=read();
p.v=b;
p.k=c;
head[a-1].push_back(p);
tot=max(b,tot);
}//建图
for(int i=1;i<=tot;i++){
p.k=-1;
p.v=i-1;
head[i].push_back(p);//隐藏条件2
p.k=0;
p.v=i;
head[i-1].push_back(p);//隐藏条件1
head[50002].push_back(p);//我设50002号节点为根节点,连上所有节点
}
p.k=0;
p.v=0;
head[50002].push_back(p);
spfa(50002);//spfa不是死了吗
printf("%d\n",dis[tot]);
if(--t)
cout<<endl;//注意这里的输出格式,特别坑,我wa了好多次才发现
}
return 0;
}