POJ 1275 Cashier Employment(差分约束 建模 二分)
来源:互联网 发布:菜谱软件ipad 编辑:程序博客网 时间:2024/05/21 22:48
POJ 1275
题目大意
一个商店每天24个时段各有一个需要的职工数
分析
尝试以不同的方式去描述一个问题是着手分析的一个很好的方式,将一个问题数学化也是一种常用的方法。
错误思路
注意到职工数n最多有1000个,但是开始时间
ti 的情况最多只有23中,也就是说大多数职工其实是等价的,可以合并起来处理。重述一下问题:设
xi 表示在时间i开始工作的员工数,由于这个时间开始工作的员工数是有限的,所以需要满足约束条件(0≤xi≤Ci) 。令yi 表示在时段i工作的职工数,yi 可以由x 得出。变成形如下面的约束方程⎧⎩⎨⎪⎪⎪⎪⎪⎪xa1+xa2+...+xak≥R0xb1+xb2+...+xbk≥R1...求min(x0+x1+...x23)
这种形式的整数规划是一个NP-hard问题,这个问题可以归约到0-1整数规划,但也只是这种形式的整数规划的特殊形式,这种形式的整数规划并不能还原到我们的这个问题上去,也就是说我们要求解的问题和这种形式的整数规划并不是等价的。因此不能从这种形式的整数规划的普遍解法的角度考虑这个问题,可以通过观察这个约束方程的特征希望能够找到优化的方法是一个思路。我们应该注意到一个规律就是:如果将
x 按照职工开始工作的时间进行编号的话,那么约束方程的每一个约束不等式的编号将是连续的,并且每个不等式的变量个数是相同的。也就是说不等式是形如:
⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪x17+x18+...+x23+x0≥R0x18+...+x23+x0+x1≥R1...x16+x17+...+x22+x23≥R23求min(x1+x2+...x23)
根据这条启发式信息,既然每个不等式的变量数相同都为8且具有相同的7项,那么可以通过两式相减就变成形如
a−b≥c 的经典差分约束不等式了:⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪x17−x1≥R0−R1x18−x2≥R1−R2...x15−x23≥R22−R23x16−x0≥R23−R0
要求min(x0+x1+...+x23) 我们可以新建一个源点
x24=0 再加上每个变量满足
(0≤xi≤ci) 条件:{x24−xi≥−Cixi−x24≥0
但是这样是没法求出
min(x0+x1+...+x23) 的然后就卡在这里了!!!
再分析
想不出思路后,百度,在这里继续写一下分析的过程:
既然将
x0,x1...x23 分开求是得不到它们和的最小值的,那么我们可以用一个变量si 表示时刻i及之前实际开始工作的总职工数。那么有(s−1=0) ⎧⎩⎨0≤si−si−1≤Cisi−s(i−8)≥Risi+s23−si+16≥Ri0≤i≤238≤i≤230≤i≤7
转化成标准形式后就是(下标做了+1处理):⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪si−si−1≥0si−1−si≥−Cisi−s(i−8)≥Risi−s(i+16)≥Ri−s24s24−s0≥s24求min(s24)1≤i≤241≤i≤248≤i≤231≤i≤7因为s24需要等于ans
由于上面第四个不等式由三个变量,但s24 比较特殊,所以可以用二分的方法对每一个s24 判断是否可行。
总结
其实这道题也不是特别难,下标处理上稍微复杂了一点,一开始思路走错了没有想到先区间求和的处理。
又是一道弄了一天的题。。。不过就是要多做点这样的题才能使自己的能力提升。
看见博客有用单纯形法求解线性规划的,虽然效率低一点了,但很通用啊,有空学习一下:POJ1275 Cashier Employment[差分约束系统 || 单纯形法]
代码
#include<cstdio>#include<iostream>#include<cmath>#include<cstring>#include<cstdlib>#include<queue>#include<map>#include<algorithm>#include<set>using namespace std;const int INF=0x7fffffff;int T;int R[25];int n;int C[25];//C[i]表示以i作为开始时间的时段的职工数目int s[25];struct Edge{ int to; int next; int w;}edge[201005];int edgecount;int flag;//flag=0表示无环int head[1005];int dis[1005];int vis[1005];int in[1005];//表示某个点进队的次数void Init(){ memset(head,-1,sizeof(head)); memset(vis,0,sizeof(vis)); memset(in,0,sizeof(in)); edgecount=0; flag=0;}void Add_edge(int u,int v,int w){ edge[++edgecount].to=v; edge[edgecount].w=w; edge[edgecount].next=head[u]; head[u]=edgecount;}void Spfa(int s,int ans)//无解flag=1{ for(int i=0;i<=24;i++)dis[i]=-INF; memset(vis,0,sizeof(vis)); memset(in,0,sizeof(in)); dis[s]=0; vis[s]=1;//vis为1表示在队列里面 queue<int>Q; Q.push(s); while(!Q.empty()) { int u=Q.front(); Q.pop(); for(int k=head[u];k!=-1;k=edge[k].next) { int t=edge[k].w+dis[u]; if(dis[edge[k].to]<t) { dis[edge[k].to]=t; if(vis[edge[k].to]!=1) { Q.push(edge[k].to); vis[edge[k].to]=1; in[edge[k].to]++; } if(in[edge[k].to]>24){flag=1;return ;} } } vis[u]=0; } if(dis[24]!=ans)flag=1;}void Build(int ans){ int sum=0; for(int i=1;i<=24;i++) { Add_edge(i,i-1,-C[i]); Add_edge(i-1,i,0); } for(int i=9;i<=24;i++) Add_edge(i-8,i,R[i]); for(int i=1;i<=8;i++) Add_edge(i+16,i,R[i]-ans); Add_edge(0,24,ans);}void Solve()//二分{ int L=0; int R=n; int M; int ans=-1; while(L<R) { M=(L+R)/2; Init(); Build(M); Spfa(0,M); if(flag==0) { ans=M; R=M; } else L=M+1; } if(ans!=-1){cout<<ans<<endl;} else cout<<"No Solution"<<endl;}int main(){ scanf("%d",&T); int t; int ans; while(T--) { ans=0; memset(C,0,sizeof(C)); for(int i=1;i<=24;i++)scanf("%d",&R[i]); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&t); C[t+1]++; } Solve(); } return 0;}
- POJ 1275 Cashier Employment(差分约束 建模 二分)
- POJ 1275 Cashier Employment(差分约束系统+二分)
- POJ 1275 Cashier Employment (差分约束 二分)
- POJ--1275[Cashier Employment] 差分约束
- poj-1275-Cashier Employment-差分约束
- poj 1275 Cashier Employment 差分约束
- POJ 1275 Cashier Employment 差分约束
- poj 1275 Cashier Employment 【差分约束】【经典建模】 【最短路求法 + 最长路求法】
- POJ 1275 Cashier Employment(差分约束系统)
- poj 1275 Cashier Employment(差分约束#6)
- POJ 1275 Cashier Employment(差分约束)#by zh
- POJ 1275-Cashier Employment(差分约束系统)
- POJ 1275--Cashier Employment【差分约束,经典建边】
- 差分约束学习(二)POJ 1275:Cashier Employment
- POJ 1275Cashier Employment (差分约束 + spfa)
- poj——1275 Cashier Employment 差分约束系统
- POJ 1275 Cashier Employment(差分约束)
- Cashier Employment poj 1275 差分约束系统
- 如何设计一触式微交互
- 时间序列分析-R语言-随机游走以及回归画图
- JS中的与时间相关的函数(long与date,timestamp之间的转换)
- LeetCode 1. Two Sum
- 动态下拉框
- POJ 1275 Cashier Employment(差分约束 建模 二分)
- 唯一性索引(Unique Index)与普通索引(Normal Index)差异(上)
- GDKOI2017总结
- Android自定义View的三种实现方式
- Docker与Kubernetes系列(四): Docker的数据卷
- Android图片压缩(质量压缩和尺寸压缩)&Bitmap转成字符串上传
- EDA软件_Cadence_OrCAD Capture自带元件库汇总
- Project interpreter not specified(eclipse+pydev)
- sqoop1.4.6报错:ERROR sqoop.Sqoop: Got exception running Sqoop: java.lang.RuntimeException: Could not l