POJ1275 Cashier Employment

本文探讨了如何通过图论中的差分约束系统解决一个特定的问题。作者介绍了建立不等式模型的方法,并详细解释了三个关键不等式的含义。此外,还提供了完整的C++代码实现,包括节点结构定义、初始化、添加边、SPFA算法等步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 最近觉得图论的很多题目都是难在建模。。。这题虽然是比较明显的差分约束但是一直没能建出不等式模型,后来在搜索相关资料的时候看到了建模方法,在纠结了一阵子之后终于干掉了。

首先我们设定三个数组num[i](i时刻能够开始工作的人数)、s[i](实际雇佣的人数到i之和)、r[i](i时刻至少需要的人数)

那么可以直观的得出以下几个不等式:

(1)、0 <= s[i]-s[i-1]<=num[i];(i>=1 && i <= 24)

(2)、s[i] - s[i-8] >= r[i];(i >= 8 && i <= 24)

(3)、s[23] - (s[i+16] - s[i]) >= r[i];(i>=1 && i < 8)

第三个式子移项后可得s[i+16]-s[i] <= s[24] - r[i];

可以发现,如果我们设定s为未知量求解差分约束方程则s[24]为未知量,那么定然无法求解,因而需要枚举s[24]从0~m,如果这样的话有可能枚举到的结果j小于s[24],所以要增加一个新的约束s[24]>=j,即增加边24->0;为了防止负数和死循环,最好数组下标从1开始

 

#include <iostream>
#include <string.h>
using namespace std;
const int MAXN = 30;
const int MAXM = MAXN*MAXN;
int num[25], s[25], r[25];//i时刻能够开始工作的人数、实际雇佣的人数到i之和、至少需要的人数; 
struct node
{
       int v, w, next;       
}mapp[MAXM];
int id;
int head[MAXN];
void init()
{
     memset(head, -1, sizeof(head));
     id = 0;     
}
void addedge(int u, int v, int value)
{
     mapp[id].v = v, mapp[id].w = value, mapp[id].next = head[u], head[u] = id ++; 
}
int dist[MAXN];
bool inque[MAXN];
const int inf = 1 << 30;
int in[MAXN] = {0};
int que[100*MAXN];
bool SPFA(int s, int n)
{
     memset(inque, false, sizeof(inque));
     memset(in, 0, sizeof(in));
     for (int i = 0; i <= n; i ++){
         dist[i] = inf;    
     }
     int front, rear;
     front = rear = 0;
     que[rear ++] = s;
     inque[s] = true;
     dist[s] = 0;
     in[s] = 1;
     while (front < rear){
           int pre = que[front ++];
           inque[pre] = false;
           for (int i = head[pre]; i != -1; i = mapp[i].next){
               if (dist[mapp[i].v] > dist[pre] + mapp[i].w){
                  dist[mapp[i].v] = dist[pre] + mapp[i].w;
                  if (!inque[mapp[i].v]){
                     inque[mapp[i].v] = true;                       
                     in[mapp[i].v] ++;
                     que[rear ++] = mapp[i].v;
                     if (in[mapp[i].v] > 24)return false;//判断是否有无解情况,因为每个点最多入队24次 
                     
                  }                    
               }    
           }      
     }
     return true;
}

int main()
{
    int t;
    scanf("%d", &t);
    while ( t --){ 
          for (int i = 1; i <= 24; i ++){
              scanf("%d", &r[i]);
          }      
          int m;
          scanf("%d", &m);
          memset(num, 0, sizeof(num));
          for (int i = 0; i < m; i ++){
                int time;
                scanf("%d", &time);
                num[time+1] ++;           
          }
          init();
          int minn = -1;
          for (int j = 0; j <= m; j ++){ 
              init();
              for (int i = 1; i <= 24; i ++){
                  addedge(i-1, i, num[i]);
                  addedge(i, i-1, 0);
                  if (i >= 8 && i <= 24)
                     addedge(i, i-8, -r[i]);
                   else addedge(i, i+16, j-r[i]);
              }
              addedge(24, 0, -j);
              if (SPFA(0, 25)){minn = j;break;}
          }
    
          minn == -1 ?printf("No Solution\n") : printf("%d\n", minn);
          
    } 
    return 0;    
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值