非常早之前整理的差分约束,做题用到,发现都忘了
差分约束
如果一个系统由 个变量 个约束条件组成,每个约束条件均为形如 的不等式 (),则称其为差分约束系统。
(1)求不等数组的可行解
 源点需要满足的条件:从源点出发,一定可以走到所有的边,(不是一定要走到所有的点,因为对于孤立的点来说点的取值是不影响不等式是否成立的)
 步骤:
- 
先将每个不等式 转化成一条从 
- 
找到一个超级源点,使得该源点一定可以遍历到所有的边 
- 
从源点求一遍单源最短路  结果1:如果存在负环,则原不等式组一定无解(通过数学推导得到)  结果2:如果没有负环,则dist数组就是原不等式组的一个可行解。 
(2)求最大最小值(这里的最大值最小值指的是每个变量的最值)
 结论: 如果求得是最小值,应该求最长路;如果求得是最大值,应该求最短路
 问题: 如何转化
 方法:建立一个超级源点, 0 号节点,然后建立从 0 -> i 的边 , 长度是 c 的边即可.
 以求 的最大值为例,求所有从xi 出发,构成的不等式链
	所计算出的上界,最终的 是所有上界的最小值.

做题实录
雇佣收银员 差分约束+枚举
尝试使用前缀和的思想去构造不等式组,不清楚怎么表达8小时工作关系。
看了mrk和y总视频讲解了搞懂了这题(超级不错)
													
观察到 0 号点可以作为超级源点,所以一共有25个点,就是题目的答案,可以通过枚举的方法,每次枚举都建立新图,跑spfa 。
特别需要注意的一点,是定值,所以 
const int N=30,M=1e9+7;
ll n,m,_;
int num[25],x[25],s[25],r[25];
//一共有25个点,给30个余额的,3*n的边
int h[N],e[N*3],ne[N*3],w[N*3],idx;
void add(int a,int b,int c){
	e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
int dist[N],cnt[N];
bool st[N];
void build(int s24){
	idx=0;
	mem(h,-1);
	for(int i=1;i<=24;i++){
	    add(i-1,i,0);
		add(i,i-1,-num[i]);
	}
	for(int i=8;i<=24;i++){
		add(i-8,i,r[i]);
	}
	for(int i=1;i<=7;i++){
		add(i+16,i,r[i]-s24);
	}
	add(24,0,-s24);
	add(0,24,s24);
}
bool spfa(int s24)
{
	build(s24);//将建图内置到spfa中,tql
	mem(dist,-0x3f);// 跑最长路
	mem(st,0);
	mem(cnt,0);
	queue<int>que;
	que.push(0);
	st[0]=1;
	dist[0]=0;
	while(que.size()){
		auto t=que.front();
		que.pop();
		st[t]=0;
		for(int i=h[t];~i;i=ne[i]){
			int j=e[i];
			if(dist[j]<dist[t]+w[i]){//求一个最长路
				dist[j]=dist[t]+w[i];
				cnt[j]=cnt[t]+1;
				if(cnt[j]>=25)return 0;// 0是超级源点,25个点
				if(!st[j]){
					que.push(j);
					st[j]=1;
				}
			}
		}
	}
	return 1;
}
void solve()
{
    
	for(int i=1;i<=24;i++){
		cin>>r[i];
	}
	cin>>n;
	mem(num,0);
	for(int i=0;i<n;i++){
		int x;cin>>x;
		x++;//所有的点向后移动一位
		num[x]++;
	}
	
	bool flag=false;
	for(int i=0;i<=1000;i++){
		if(spfa(i)){
			cout<<dist[24]<<endl;
			flag=true;
			break;
		}
	}
	if(!flag){
		puts("No Solution");
	}
	
}
int main()
{
	cin>>_;
	while(_--)
	{
		solve();
	}
	return 0;
}
还可以进行二分答案优化
bool flag=false;
int l=0,r=n;
while(l<r){
    int mid=l+r>>1;
    if(spfa(mid)){
        r=mid;
    }
    else{
        l = mid + 1;
    }
}
if(spfa(r)){
    cout<<dist[24]<<endl;
}else{
    puts("No Solution");
}










