pku1275 差分约束

Cashier Employment

由于数据量小,用Bellman_Ford就能过,而且不用要源点。

这道差分约束题困了我好久,WA了好多次,主要是不理解题意,在那乱写,后来WA之后,看别人解题报告,又是狂改,最后还是没能过!今天早上,在真正理解之后,把需要修改地方给删了,又重写了一下,终于找到错误了,原来边数赋值错了。discuss里说的n = 4的情况是误导大家的,其实是少写了个条件,题目和数据都是没问题的!

这题《算法艺术与信息学竞赛》中有解答,主要有四种情况:

2010072410342789.jpg

这题我就是用二分做的,对sum能取到的值二分,在这里有一个点s[-1],我是将所有点都往后移一位来处理的,就空出一个0点可以代替这里的-1点,n = 4的情况就是这里的第三种情况没有考虑造成的。

多于第四个式子可以这样解释:第i个小时雇佣的出纳员数 = 8小时以前雇佣的出纳员数+第i个小时需要的出纳员数(因为这第i个小时的出纳员可以是前8个小时中任意一个小时雇佣的,因为他会一直工作8个小时,也就覆盖到第i个小时了^-^);

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
#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 ;
}

 

转载于:https://www.cnblogs.com/ylfdrib/archive/2010/07/24/1784201.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值