记录编号 290266 评测结果 AAAAAAAAAA
题目名称 [POJ1275]出纳员的雇佣 最终得分 100
用户昵称 GravatarSky_miner 是否通过 通过
代码语言 C++ 运行时间 0.008 s
提交时间 2016-08-06 06:08:40 内存使用 0.29 MiB
显示代码纯文本
  1. /*
  2. 设num[ i ]为i时刻能够开始工作的人数,x[ i ]为 第 i 时刻实际雇佣的人数,那么x[ I ]<=num[ I ]。
  3. 设r[ i ](输入的每一时刻所需的人数)为i时刻至少需要工作的人数,于是有如下关系:
  4. x[ I-7 ]+x[ I-6 ]+x[ I-5 ]+x[ I-4 ]+x[ I-3 ]+x[ I-2 ]+x[ I-1 ]+x[ I ]>=r[ I ]
  5. 设s[ I ]=x[ 1 ]+x[ 2 ]…+x[ I ],得到
  6. 0<=s[ I ]-s[ I-1 ]<=num[ I ], 0<=I<=23
  7. s[ I ]-s[ I-8 ]>=r[ I ], 8<=I<=23 建立关系
  8. s[ 23 ]+s[ I ]-s[ I+16 ]>=r[ I ], 0<=I<=7 建立可以循环的关系
  9. 对于以上的几组不等式,我们采用一种非常笨拙的办法处理这一系列的不等式(其实也是让零乱的式子变得更加整齐,易于处理)。
  10. 首先我们要明白差分约束系统的应用对象(它通常针对多个二项相减的不等式的)
  11. 于是我们将上面的所有式子都转化成两项未知项在左边,另外的常数项在右边,且中间用>=连接的式子,即:
  12. s[ I ] - s[ I-1 ] >= 0 (0<=I<=23)
  13. s[ I-1 ] - s[ I ] >= -num[ I ] (0<=I<=23)
  14. s[ I ]-s[ I-8 ]>=r[ I ] (8<=I<=23)
  15. s[ I ]-s[ I+16 ]>=r[ I ]-s[ 23 ] (0<=I<= 7)
  16. S[23] - 0 >= sum;sum为雇佣的出纳员总数
  17. */
  18. //好麻烦的关系转换,,,对差分约束不会再有爱了。。。
  19. #include <cstdio>
  20. #include <cstring>
  21. using namespace std;
  22. template<typename T>inline void read(T &x){
  23. x=0;char ch;bool flag = false;
  24. while(ch=getchar(),ch<'!'); if( ch == '-' ) ch=getchar(),flag = true;
  25. while(x=10*x+ch-'0',ch=getchar(),ch>'!');if( flag ) x=-x;
  26. }
  27. int n,m,p,ecnt,T;
  28. int dis[30],cnt[30],r[30],t[30];
  29. const int INF = 1e9;
  30. int to[100],head[30],he[30],ne[100]={0},w[100]={0};
  31. inline void add(int u,int v,int c){
  32. to[++ecnt] = v;
  33. w[ecnt] = c;
  34. ne[ecnt] = head[u];
  35. head[u] = ecnt;
  36. }
  37. int Q[100],qhead = 1,qtail = 99,size = 0;
  38. bool flag[100];
  39. inline int top(){
  40. int x = Q[qhead];
  41. if( ++qhead == 100 )qhead=1;
  42. --size;
  43. flag[x] = false;
  44. return x;
  45. }
  46. inline void push_front(int x){
  47. flag[x] = true;
  48. ++size;
  49. if( !(--qhead) ) qhead=99;
  50. Q[ qhead ] = x;
  51. }
  52. inline void push_back(int x){
  53. flag[x] = true;
  54. ++size;
  55. if(++qtail == 100) qtail = 1;
  56. Q[qtail] = x;
  57. }
  58. inline bool spfa(int mid){
  59. for(int i = 0;i <= 24; ++i) dis[i] = -INF,cnt[i] = 0;
  60. cnt[0] = 1;dis[0] = 0;
  61. push_back(0);
  62. while( size ) for(int x=top(),i=head[x];i;i=ne[i])
  63. if( dis[ to[i] ] < dis[x] + w[i]){
  64. dis[ to[i] ] = dis[x] + w[i];
  65. if( !flag[to[i]] ){
  66. if( ++cnt[to[i]] > 24) return 0;
  67. if( size && dis[Q[qhead]] <= dis[to[i]]) push_front(to[i]);
  68. else push_back(to[i]);
  69. }
  70. }
  71. if(dis[24] == mid) return 1;
  72. return 0;
  73. }
  74. int main(){
  75. freopen("cashieremployment.in","r",stdin);
  76. freopen("cashieremployment.out","w",stdout);
  77. read<int>(T);
  78. while(T--){
  79. for(int i=1;i<=24;++i) read<int>(r[i]);
  80. for(int i=0;i<=24;++i) t[i] = head[i] = 0;
  81. read<int>(n);
  82. ecnt = 0;
  83. int x;
  84. for(int i=1;i<=n;++i) read<int>(x),t[x+1]++;
  85. for(int i=1;i<=24;++i) add(i-1,i,0),add(i,i-1,-t[i]);
  86. for(int i=0;i<=24;++i) he[i] = head[i];
  87. int ans = -1,L = 0,R = n;
  88. while(L<=R){
  89. int mid = (L+R)>>1;ecnt=48;
  90. for(int i=0;i<=24;++i)head[i]=he[i];
  91. add(0,24,mid);
  92. for(int i=1;i<=8;++i)add(i+16,i,r[i]-mid);
  93. for(int i=9;i<=24;++i)add(i-8,i,r[i]);
  94. if(spfa(mid)) ans = mid,R = mid-1;
  95. else L=mid+1;
  96. }
  97. if(ans == -1) printf("No Solution\n");
  98. else printf("%d\n",ans);
  99. }
  100. return 0;
  101. }