P2053 [SCOI2007]修车(逆向思维分层建图)
发布日期:2021-06-30 10:20:33 浏览次数:3 分类:技术文章

本文共 2614 字,大约阅读时间需要 8 分钟。

得 先 把 题 意 转 化 一 下 , 否 则 无 法 建 图 得先把题意转化一下,否则无法建图 ,

为 啥 没 办 法 建 图 ? 因 为 每 个 师 傅 修 每 辆 车 的 代 价 不 是 为啥没办法建图?因为每个师傅修每辆车的代价不是 ?定值

不 是 定 值 , 就 想 办 法 变 成 定 值 。 不是定值,就想办法变成定值。 ,

考 虑 某 个 师 傅 一 次 修 车 a 1 , a 2 , a 3 , a 4 考虑某个师傅一次修车a_1,a_2,a_3,a_4 a1,a2,a3,a4

那 么 a 1 的 等 待 时 间 是 a 1 那么a_1的等待时间是a_1 a1a1

a 2 的 等 待 时 间 是 a 1 + a 2 a_2的等待时间是a_1+a_2 a2a1+a2

a 3 的 等 待 时 间 是 a 1 + a 2 + a 3 a_3的等待时间是a_1+a_2+a_3 a3a1+a2+a3

a 4 的 等 待 时 间 是 a 1 + a 2 + a 3 + a 4 a_4的等待时间是a_1+a_2+a_3+a_4 a4a1+a2+a3+a4

设 某 个 师 傅 修 了 x 辆 车 设某个师傅修了x辆车 x

最 后 修 的 车 的 代 价 只 需 要 在 原 来 基 础 上 乘 1 最后修的车的代价只需要在原来基础上乘1 1

倒 数 第 二 次 修 车 的 代 价 只 需 要 在 原 来 的 基 础 上 乘 2 倒数第二次修车的代价只需要在原来的基础上乘2 2

. . . . . . . . . . . . . . . . . . . . . . ...................... ......................

于 是 把 m 个 师 傅 分 成 n 层 于是把m个师傅分成n层 mn

第 i 层 表 示 修 倒 数 第 i 辆 车 的 师 傅 , 那 么 代 价 乘 以 i 第i层表示修倒数第i辆车的师傅,那么代价乘以i ii,i

每 层 的 每 个 师 傅 向 每 一 辆 车 连 边 即 可 每层的每个师傅向每一辆车连边即可

跑 最 小 费 用 最 大 流 , 对 于 每 个 师 傅 而 言 一 定 是 依 次 选 择 跑最小费用最大流,对于每个师傅而言一定是依次选择 ,

修 倒 数 第 1 辆 车 , 修 倒 数 第 2 辆 车 , 实 际 上 这 也 是 连 续 的 修倒数第1辆车,修倒数第2辆车,实际上这也是连续的 1,2,

#include 
using namespace std;const int maxn=2e5+10;const int inf=1e9; int n,m,s,t,c[509][509];struct edge{ int to,nxt,flow,w;}d[maxn]; int head[maxn],cnt=1;void add(int u,int v,int w,int flow){ d[++cnt]=(edge){v,head[u],flow,w},head[u]=cnt; d[++cnt]=(edge){u,head[v],0,-w},head[v]=cnt;}int dis[maxn],mincost,vis[maxn],pre[maxn],flow[maxn];bool spfa(){ for(int i=0;i<=t;i++) dis[i]=inf,vis[i]=0; dis[s]=0,flow[s]=inf; queue
q; q.push( s ); while( !q.empty() ) { int u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i;i=d[i].nxt ) { int v=d[i].to; if( d[i].flow&&dis[v]>dis[u]+d[i].w ) { dis[v]=dis[u]+d[i].w; flow[v]=min(flow[u],d[i].flow); pre[v]=i; if( !vis[v] ) vis[v]=1,q.push( v ); } } } return dis[t]!=inf;}int dinic(){ while( spfa() ) { int x=t; mincost+=flow[t]*dis[t]; while( x!=s ) { int i=pre[x]; d[i].flow-=flow[t]; d[i^1].flow+=flow[t]; x=d[i^1].to; } }}int main(){ cin >> m >> n;//m位技术人员,n位车主 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin >> c[i][j]; s=0,t=n*m+n+1; for(int i=1;i<=n*m;i++) add(s,i,0,1);//源点连向每个师傅 for(int i=1;i<=m;i++)//枚举每个师傅 for(int j=1;j<=n;j++)//枚举每个车 for(int k=1;k<=n;k++)//枚举每个时刻 { int id=(k-1)*m+i;//第k层图,每层图有m个师傅 add(id,j+n*m,c[j][i]*k,1); } for(int i=1;i<=n;i++) add(n*m+i,t,0,1); dinic(); printf("%.2lf",double(mincost)/(n*1.0) );}

转载地址:https://issue-is-vegetable.blog.csdn.net/article/details/108165978 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:P2057 [SHOI2007]善意的投票 / [JLOI2010]冠军调查
下一篇:B. Ternary Sequence(贪心或最小费用最大流)

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2024年04月11日 05时21分03秒