bzoj 1070: [SCOI2007]修车
2016-04-05 21:32
211 查看
1070: [SCOI2007]修车
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 4032 Solved: 1643
[Submit][Status][Discuss]
Description
同一时刻有N位车主带着他们的爱车来到了汽车维修中心。维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的。现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最小。 说明:顾客的等待时间是指从他把车送至维修中心到维修完毕所用的时间。Input
第一行有两个m,n,表示技术人员数与顾客数。 接下来n行,每行m个整数。第i+1行第j个数表示第j位技术人员维修第i辆车需要用的时间T。Output
最小平均等待时间,答案精确到小数点后2位。Sample Input
2 23 2
1 4
Sample Output
1.50HINT
数据范围: (2<=M<=9,1<=N<=60), (1<=T<=1000)Source
题解:费用流神题,真正困扰了一晚上啊。刚开始时想法就跑偏了,想着用后来修的车给前面修的车补流,但是搞来搞去发现貌似不对,然后就弃疗了 T_T
还是来看看正确的神建图吧。
考虑第i个工人,他修第j辆车只对后面要修的车有影响,而前面修过的车已经对当前没有影响了。
而这个影响就是后面每个将要修理的车都多等待了time的时间。
把每个工人拆成n个点,表示第几个工人第几次修车。
每个车跟所有n×m个工人拆出的点连边。流量为1,费用为time[i,j]×k。(这里的k表示是倒数第几个修的)
源点和每辆车连边,n×m个表示工人的点和汇点连边,流量都为1,费用同为0。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<cmath> #define N 100000 using namespace std; int n,m,cnt,tot=-1,dis ,can ,last ; int next[N*2],point ,v[N*2],remain[N*2],c[N*2],minn,flow; int mincost=0; bool vis ; const int inf=1e9; void add(int x,int y,int z,int k) { tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z; c[tot]=k; tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0; c[tot]=-k; } int addflow(int s,int t) { int now=t; int ans=inf; while (now!=s) { ans=min(ans,remain[last[now]]); now=v[last[now]^1]; } now=t; while (now!=s) { remain[last[now]]-=ans; remain[last[now]^1]+=ans; now=v[last[now]^1]; } return ans; } bool spfa(int s,int t) { memset(dis,0x7f,sizeof(dis)); memset(can,0,sizeof(can)); dis[s]=0; can[s]=1; queue<int> p; p.push(s); while(!p.empty()) { int now=p.front(); p.pop(); for (int i=point[now];i!=-1;i=next[i]) if (dis[v[i]]>dis[now]+c[i]&&remain[i]) { dis[v[i]]=dis[now]+c[i]; last[v[i]]=i; if (can[v[i]]==0) { can[v[i]]=1; p.push(v[i]); } } can[now]=0; } if (dis[t]>inf) return false; int k=addflow(s,t); mincost+=k*dis[t]; return true; } void maxflow(int s,int t) { while (spfa(s,t)); } int main() { memset(point,-1,sizeof(point)); memset(next,-1,sizeof(next)); scanf("%d%d",&m,&n); for(int i=1;i<=n;i++) add(0,i,1,0); for (int i=1;i<=n;i++) { for (int j=1;j<=m;j++) { int x; scanf("%d",&x); for (int k=1;k<=n;k++) add(i,(j-1)*n+k+n,1,x*k); } } cnt=n+n*m+1; for (int i=1;i<=m*n;i++) add(i+n,cnt,1,0); maxflow(0,cnt); //cout<<flow<<endl; printf("%0.2lf\n",(double)(mincost*1.0/n)); }
相关文章推荐
- 正则表达式(1) -- 正则表达式基础
- 应用程序域
- 使用FileReader读取本地磁盘文件问题
- 解析java为什么不能创建FilterInputStream流
- js高级----流程控制
- 客户端存储之HTML5 web存储
- 模拟赛 cf#304div2 D.Soldier and Number Game ,人生中第一次在比赛中A掉D题,好吧我承认这个D题有点水
- js之apply,call浅谈
- 选择
- Java入门:基础算法之检查奇偶性
- PAT-A-1051 Pop Sequence 【栈】
- 学习Python
- iOS音频播放
- POJ-2002 Squares
- Win7环境下STAF安装STAX遇到的问题及解决方法
- c++常用特性原理解析
- linux下的网络模型
- kvm
- 学习Python
- 【转】浅谈Java中的equals和==