由于数据量小,用Bellman_Ford就能过,而且不用要源点。
这道差分约束题困了我好久,WA了好多次,主要是不理解题意,在那乱写,后来WA之后,看别人解题报告,又是狂改,最后还是没能过!今天早上,在真正理解之后,把需要修改地方给删了,又重写了一下,终于找到错误了,原来边数赋值错了。discuss里说的n = 4的情况是误导大家的,其实是少写了个条件,题目和数据都是没问题的!
这题《算法艺术与信息学竞赛》中有解答,主要有四种情况:
这题我就是用二分做的,对sum能取到的值二分,在这里有一个点s[-1],我是将所有点都往后移一位来处理的,就空出一个0点可以代替这里的-1点,n = 4的情况就是这里的第三种情况没有考虑造成的。
多于第四个式子可以这样解释:第i个小时雇佣的出纳员数 = 8小时以前雇佣的出纳员数+第i个小时需要的出纳员数(因为这第i个小时的出纳员可以是前8个小时中任意一个小时雇佣的,因为他会一直工作8个小时,也就覆盖到第i个小时了^-^);
#include < stdio.h >
#define INF 0xfffffff
#define NN 26
#define MM 100
int edNum, N, sum;
struct node{
int s, e, v;
}edge[MM];
int dis[NN];
int r[NN];
int t[NN];
void add( int a, int b, int c){
edge[edNum].s = a;
edge[edNum].e = b;
edge[edNum].v = c;
edNum ++ ;
}
void change( int ans){
int i, sta, end;
// 开始就这个地方错了,当成24赋值了
edNum = 48 ;
for (i = 1 ; i <= 24 ; i ++ ){
// 这个地方的处理也成为这一题的关键
if (i > 8 ){
add(i, i - 8 , - r[i]);
} else {
add(i, i + 16 , ans - r[i]);
}
}
// 这里就是为什么n = 4 很多人过不了
add( 24 , 0 , - ans);
}
int Bellman_Ford(){
int i, j;
for (i = 0 ; i <= 24 ; i ++ ) dis[i] = INF;
for (i = 0 ; i <= 24 ; i ++ ){
for (j = 0 ; j < edNum; j ++ ){
if (dis[edge[j].e] > dis[edge[j].s] + edge[j].v){
dis[edge[j].e] = dis[edge[j].s] + edge[j].v;
}
}
}
for (j = 0 ; j < edNum; j ++ ){
if (dis[edge[j].e] > dis[edge[j].s] + edge[j].v){
return 0 ;
}
}
return 1 ;
}
/* 这里用的二分来查找最小的ans */
void solve( int sum)
{
int low = 0 ;
int hig = sum;
int ans = - 1 ;
do {
int mid = (low + hig) >> 1 ;
change(mid);
if (Bellman_Ford()){
ans = mid;
hig = mid - 1 ;
}
else low = mid + 1 ;
} while (low <= hig);
if (ans == - 1 ) puts( " No Solution " );
else printf( " %d\n " , ans);
}
int main()
{
int T, i, R, k;
scanf( " %d " , & T);
while (T -- ){
sum = 0 ;
edNum = 0 ;
for (i = 1 ; i <= 24 ; i ++ ){
scanf( " %d " , & r[i]);
sum += r[i];
t[i] = 0 ;
}
scanf( " %d " , & N);
if (N < sum){
sum = N;
}
for (i = 0 ; i < N; i ++ ){
scanf( " %d " , & k);
t[k + 1 ] ++ ;
}
for (i = 1 ; i <= 24 ; i ++ ){
add(i - 1 , i, t[i]);
add(i, i - 1 , 0 );
}
solve(sum);
}
return 0 ;
}