链接:传送门
差分约束难点在约束条件的挖掘,约束条件找不出或找不全就无法准确的做出这类型题目。
初次碰到这道题时想了很久也没能将约束条件挖掘出来,后来参考了网上各位巨头的博客才A了此题,现在将该题的思路写出来,使自己印象更深刻。
令:
S[i]:0~i时刻雇佣的出纳员。
r[i]:每个时刻需要的出纳员。
t[i]:每个时刻应征的出纳员。
S[0]始终为0,为辅助点。
mid为对给出应征的出纳员的总数的二分值
则有:
S[i-1] - S[i] <= 0;
S[i] - S[i-1] <= t[i];
S[i] - S[j] <= mid - r[j]; ( i > j )
S[i] - S[j] <= -r[j]; ( i < j )
S[0] - S[24] <= -mid;
若存在从点0到点24的最短路,则mid为雇佣出纳员数的一个可行解。
然后进行二分,求得出纳员数的最小解。
#include <iostream>
#include <stdio.h>
#include <string>
#include <algorithm>
#include <stdlib.h>
#include <queue>
using namespace std;
#define size 100000
struct Edge
{
int node,len;
Edge*next;
}m_edge[size];
Edge*head[25];
int Ecnt;
int S[25]; //0-i时刻雇佣的出纳员
int r[25]; //每个时刻需要的出纳员
int t[25]; //每个时刻应征的出纳
bool flag[25];
int num[25];
void initData()
{
fill( S , S+25 , 99999999 );
memset( m_edge , 0 , sizeof(m_edge) );
fill( head , head+25 , (Edge*)0 );
memset( flag , false , sizeof(flag) );
memset( num , 0 , sizeof(num) );
}
void mkEdge( int a , int b , int L )
{
m_edge[Ecnt].node = a;
m_edge[Ecnt].len = L;
m_edge[Ecnt].next = head[b];
head[b] = m_edge+Ecnt++;
}
bool spfa()
{
queue<int>point;
point.push( 0 );
S[0] = 0;
flag[0] = true;
++num[0];
while( !point.empty() ){
int t = point.front();
point.pop();
flag[t] = false;
for( Edge*p = head[t] ; p ; p = p->next ){
int u = p->node;
int L = p->len;
if( S[u] > S[t] + L ){
S[u] = S[t] + L;
if( !flag[u] ){
point.push(u);
flag[u] = true;
++num[u];
if( num[u] > 25 ) return false;
}
}
}
}
return true;
}
int main()
{
int T;
scanf("%d",&T);
while( T-- ){
memset( r , 0 , sizeof(r) );
memset( t , 0 , sizeof(t) );
Ecnt = 0;
for( int i = 1 ; i <= 24 ; ++i ){
scanf("%d",&r[i]);
}
int N,p;
scanf("%d",&N);
for( int i = 0 ; i < N ; ++i ){
scanf("%d",&p);
++t[p+1];
}
int rt = N,lt = 0;
int mid;
int ans = -1;
while( lt<=rt ){
initData();
mid = (lt+rt)/2;
for( int i = 1 ; i <= 24 ; ++i ){
mkEdge( i-1 , i , 0 );
mkEdge( i , i-1 , t[i] );
}
for( int i = 1 ; i <= 24 ; ++i ){
int j = (i+8)%25;
if( i > j ) mkEdge( i , j+1 , mid-r[j+1] );
if( i < j ) mkEdge( i , j , -r[j] );
}
mkEdge( 0 , 24 , -mid );
if( spfa() ){
rt = mid-1;
ans = mid;
}
else lt = mid+1;
}
if( ans != -1 ) printf("%d\n",ans);
else printf("No Solution\n");
}
return 0;
}