[SDOI2011][bzoj2245] 工作分配 [费用流]
2018-04-08 15:45
302 查看
题面
传送门思路
数据范围n,m<=250分配任务问题
这是典型的“看到数据范围就知道算法”类型
而且我们发现我们要保证一定产出的情况下最小化花费
这句话等价于保证一定流量的情况下最小化费用
所以先确定算法:最小费用最大流
再观察一下,我们发现这道题的费用和人唯一相关,而且人和物品之间的关系是独立的
因此我们建立一个网络流图,其中包含S,T,人点和物品点
对于每个物品i,我们连边(i,T),费用0,流量为$C_i$
对于一个人i可以操作物品j,我们连边(i,j),费用0,流量inf
接下来的问题就是处理人的费用了
我们发现这道题的费用是分段处理的
看到分段,第一想法就是把人拆点,但是这样势必会大大增加冗余边数,拖慢程序速度
因此我们考虑不拆点来做
观察发现,这道题分段中保证$W_{i,j}$递增
也就是说,如果有一坨重边,我们的算法会先跑代表靠前的分段的边
这引导我们往重边方向上想
对于一个点i,我们把每个长度为l,段中费用为cost的分段,连一条边(S,i),费用cost,流量l
因为每个点最多六段,所以这个算法的边数很少,跑得过
最后只要一步(S,T)费用流,输出总费用就可以了
Code:
这题卡常数啊......而且我的zkw费用流被卡了过不了,洛谷评测机又不稳定,一会TLE一会RE的......
// luogu-judger-enable-o2 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define inf 1e9 #define ll long long using namespace std; inline ll read(){ ll re=0,flag=1;char ch=getchar(); while(ch>'9'||ch<'0'){ if(ch=='-') flag=-1; ch=getchar(); } while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar(); return re*flag; } ll first[5010],dis[5010],vis[5010],n,m,cnt=-1,ans; struct edge{ ll to,next,w,cap; }a[600010]; inline void add(ll u,ll v,ll w,ll cap){ a[++cnt]=(edge){v,first[u],w,cap};first[u]=cnt; a[++cnt]=(edge){u,first[v],-w,0};first[v]=cnt; } ll q[1000010]; ll limit[5010],pre[5010]; bool Spfa(int s,int t){ ll head=0,tail=1,i,u,v,w; memset(dis,-1,sizeof(dis));memset(vis,0,sizeof(vis)); memset(limit,0,sizeof(limit));memset(pre,-1,sizeof(pre)); q[0]=s;dis[s]=0;vis[s]=1;limit[s]=inf; while(head<tail){ u=q[head++];vis[u]=0; for(i=first[u];~i;i=a[i].next){ v=a[i].to;w=a[i].w; if(a[i].cap&&((dis[v]==-1)||(dis[v]>dis[u]+w))){ dis[v]=dis[u]+w;pre[v]=i; limit[v]=_min(limit[u],a[i].cap); if(!vis[v]) q[tail++]=v,vis[v]=1; } } } return ~dis[t]; } int mcmf(int s,int t){ int re=0,u; while(Spfa(s,t)){ re+=limit[t]; for(u=t;~pre[u];u=a[pre[u]^1].to){ a[pre[u]].cap-=limit[t];a[pre[u]^1].cap+=limit[t]; ans+=limit[t]*a[pre[u]].w; } } return re; } int main(){ memset(first,-1,sizeof(first)); m=read();n=read();ll i,j,t1,t2[10],t3; for(i=1;i<=n;i++) t1=read(),add(0,i,0,t1); for(i=1;i<=m;i++){ for(j=1;j<=n;j++){ t1=read(); if(t1) add(j,n+i,0,inf); } } for(i=1;i<=m;i++){ t1=read();t2[0]=0; for(j=1;j<=t1;j++) t2[j]=read(); for(j=0;j<t1;j++){//分段建重边 t3=read(); add(n+i,n+m+1,t3,t2[j+1]-t2[j]); } t3=read();add(n+i,n+m+1,t3,inf); } mcmf(0,n+m+1); cout<<ans<<endl; }
相关文章推荐
- 【费用流】【bzoj 2245】: [SDOI2011]工作安排
- BZOJ 2245 SDOI 2011 工作安排 费用流
- BZOJ 2245 SDOI 2011 工作安排 费用流
- bzoj 2245: [SDOI2011]工作安排(费用流)
- Bzoj 2245: [SDOI2011]工作安排(费用流)
- BZOJ 2245: [SDOI2011]工作安排( 费用流 )
- bzoj 2245 [SDOI2011]工作安排(最小费用最大流)
- BZOJ 2245: [SDOI2011]工作安排
- 2245: [SDOI2011]工作安排|费用流
- 【BZOJ 2245】[SDOI2011]工作安排
- 2245: [SDOI2011]工作安排 费用流
- bzoj 2245: [SDOI2011]工作安排
- bzoj 2245 [SDOI2011]工作安排【最小费用最大流】
- bzoj2245 [SDOI2011]工作安排
- bzoj 2245 [SDOI2011]工作安排(最小费用最大流)
- 【BZOJ】【2245】【SDOI2011】工作安排
- bzoj2245 [SDOI2011]工作安排 费用流
- bzoj 2245 [SDOI2011]工作安排
- bzoj 2245 [SDOI2011]工作安排
- 2245: [SDOI2011]工作安排