1. 程式人生 > 實用技巧 >POJ 1275 Cashier Employment(差分約束)

POJ 1275 Cashier Employment(差分約束)

思路:

\(S_i\) 為前 \(i\) 個小時錄取的人數, \(num_i\) 為第 \(i\) 個小時應聘的人數,\(x_i\) 為第 \(i\) 個小時僱傭的人數,可得:

\[\begin{aligned}&(~1~)~~0\leq x_i\leq num_i=>0\leq S_i-S_{i-1}\leq num_i\\\\&(~2~)\begin{cases}S_i-S_{i-1}\geq R_i~(i\geq 8)\\S_i+S_{24}-S_{16+i}\geq R_i=>S_i-S_{16+i}~\geq R_i-S_{24}=R_i-sum(0< i<8)\end{cases}\\\\&(~3~)~~S_{24}-S_0\geq sum\end{aligned} \]

對於 \((3)\) 因為 \(S_{24}\) 我們不知道它的值,但是它表示的就是 \(sum\) 即答案,所以列舉 \(sum\) (可以二分列舉,我懶得寫了)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#define maxn 100
#define INF 0x3f3f3f3f
using namespace std;
 
int N;//個應聘者
struct node {
    int u, v, w, next;
};
 
node edge[200000];
int dist[maxn], head[maxn], used[maxn], cnt;
bool vis[maxn];
int work[maxn];//work[i]表示在第 i 個小時開始工作的人數
int need[maxn];//應聘者中可以在第i個小時開始工作的人數
 
void init (){
    cnt = 0;
    memset(head, -1, sizeof(head));
}
 
void add(int u, int v, int w){
    edge[cnt] = {u, v, w, head[u]};
    head[u] = cnt++;
}
 
void getmap(int sum){
    for(int i = 1; i <= 24; ++i){
        add(i - 1, i, 0);
        add(i, i - 1, -work[i]);
        if(i >= 8)
            add(i - 8, i, need[i]);
        else
            add(16 + i, i, need[i] - sum);
    }
    add(0, 24, sum);
}
 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue> 

using namespace std;
const int N=100,INF=0x3f3f3f3f;
struct node{
	int u,v,w,nxt;
}e[200010];

int n;
int dis[N],head[N],num[N],R[N],tot[N],cnt;//num[]表示第i小時應聘的人, R[]表示第i小時需要的人數 
bool vis[N];

inline void init(){
	cnt=0;
	memset(head,-1,sizeof(head));
}

inline void add(int u,int v,int w){
	e[++cnt].u=u;
	e[cnt].v=v;
	e[cnt].w=w;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}

inline void getsum(int sum){
	for(int i=1;i<=24;i++){
		add(i-1,i,0);
		add(i,i-1,-num[i]);
		if(i>=8) add(i-8,i,R[i]);
		else add(16+i,i,R[i]-sum);
	}
	add(0,24,sum);
}

inline bool spfa(int sum){
	for(int i=0;i<=24;i++){
		dis[i]=-INF;
		vis[i]=0;
		tot[i]=0;
	}
	dis[0]=0;
	vis[0]=1;
	tot[0]=1;
	queue<int>q;
	q.push(0);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=head[u];i!=-1;i=e[i].nxt){
			int v=e[i].v;
			int w=e[i].w;
			if(dis[v]<dis[u]+w){
				dis[v]=dis[u]+w;
				if(!vis[v]){
					vis[v]=1;
					tot[v]++;
					if(tot[v]>24) return 0;
					q.push(v);
				} 
			}
		}
	}
	return dis[24]==sum;
}

int main(){
	int T;
	scanf("%d",&T);
	int flag;
	while(T--){
		flag=0;
		memset(R,0,sizeof(R));
		memset(num,0,sizeof(num));
		for(int i=1;i<=24;i++) scanf("%d",&R[i]);
		scanf("%d",&n);
		for(int i=1,x;i<=n;i++){
			scanf("%d",&x);
			num[x+1]++;
		}
		for(int i=0;i<=n;i++){
			init();
			getsum(i);
			if(spfa(i)){
				flag=1;
				printf("%d\n",i);
				break;
			}
		}
		if(!flag) puts("No Solution");
	} 
	return 0;
}