P4016 负载平衡问题
我们对每个仓库创建两个节点XiX_iXi 和YiY_iYi ,前者为供应节点,后者为需求节点。求出最终要达到的货物值即平均数,然后把初始值处理成偏移值(初始值-平均数)。
偏移小于0。表明这个节点需要运入货物,将节点的XiX_iXi 与源点SSS 相连,容量为偏移,费用为0。
偏移大于0。表明这个节点需要运出货物,将节点的YiY_iYi 与汇点TTT 相连,容量为偏移的绝对值,费用为0。
然后再考虑相邻节点的关系。
相邻节点互相补充。将XiX_iXi 与YjY_jYj 相连,容量为+∞+ \infty+∞ ,费用为1,表示运输单位货物需要1的费用。
不是直接补充,而是作为中间节点转运。将XiX_iXi 与XjX_jXj 相连,容量为+∞+ \infty+∞ ,费用为1,意义同上。
以以上方式建图跑最小费用最大流即可。最大流保证能够平衡货物,而最小费用流能保证运输的货物最少。
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int M=210000;int n,m,ss,tt,inf=0x7fffffff;
struct danicliu{
int nex[M],cos[M],to[M],head[M],tot,vis[M],dis[M],flow[M],cap[M],id[M],pre[M],mflow,mcost;
queue<int>q;
void init(){
tot=1;memset(head,0,sizeof head);mflow=mcost=0;
}
void add(int x,int y,int z,int w){
cos[++tot]=w;
cap[tot]=z;
to[tot]=y;
nex[tot]=head[x];
head[x]=tot;
}
int bfs(int s,int t){
memset(vis,0,sizeof vis);
memset(pre,-1,sizeof pre);
memset(dis,127,sizeof dis);inf=dis[0];
dis[s]=0;q.push(s);vis[s]=1;flow[s]=inf;
while(!q.empty()){
int x=q.front();q.pop();vis[x]=0;
for(int i=head[x],tmp;i>=2;i=nex[i]){
if(dis[tmp=to[i]]>dis[x]+cos[i]&&cap[i]) {
dis[tmp]=dis[x]+cos[i];id[tmp]=i;
pre[tmp]=x;flow[tmp]=min(flow[x],cap[i]);
if(!vis[tmp]) vis[tmp]=1,q.push(tmp);
}
}
}
return dis[t]<inf;
}
void maxflow(int s,int t){
while(bfs(s,t)){
int k=t;
while(k!=s){
cap[id[k]]-=flow[t];
cap[id[k]^1]+=flow[t];
k=pre[k];
}
mflow+=flow[t];
mcost+=flow[t]*dis[t];
}
}
void adx(int x,int y,int cax,int c){
add(x,y,cax,c),add(y,x,0,-c);}
}da;int ans,val[210];
int main(){
scanf("%d",&n);int s=0,t=2000;
da.init();
for(int i=1;i<=n;i++) scanf("%d",&val[i]),ans+=val[i];
ans/=n;
for(int i=1;i<=n;i++){
val[i]-=ans;
if(val[i]>0) da.add(s,i,val[i],0),da.add(i,s,0,0);
else da.add(i+n,t,-val[i],0),da.add(t,i+n,0,0);
}
for(int i=1;i<=n;i++){
if(i!=n) da.adx(i,i+1,inf,1),da.adx(i,i+n+1,inf,1);
if(i!=1) da.adx(i,i-1,inf,1),da.adx(i,i+n-1,inf,1);
}
da.adx(1,n,inf,1),da.adx(1,2*n,inf,1),da.adx(n,1,inf,1),da.adx(n,n+1,inf,1);
da.maxflow(s,t);
printf("%d",da.mcost);
}
软件补丁问题
不知道为什么是网络流。。。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int M=510;
char s[M];
int n,m,t[M],INF,b1[M],b2[M],f1[M],f2[M],dis[1<<20+1],vis[1<<20+1];
void spfa(){
memset(dis,127/3,sizeof dis);
INF=dis[0];
dis[(1<<n)-1]=0;
queue<int>q;
q.push((1<<n)-1);vis[(1<<n)-1]=1;
while(!q.empty()){
int x=q.front();q.pop();vis[x]=0;
for(int i=1;i<=m;i++)
if(((b1[i]&x)==b1[i])&&(!(b2[i]&x))&&(dis[(x|f1[i])&(~f2[i])]>dis[x]+t[i])){
dis[(x|f1[i])&(~f2[i])]=dis[x]+t[i];
if(!vis[(x|f1[i])&(~f2[i])]) q.push((x|f1[i])&(~f2[i])),vis[(x|f1[i])&(~f2[i])]=1;
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1,len;i<=m;i++){
cin>>t[i]>>s+1;len=strlen(s+1);
for(int j=1;j<=len;j++)
if(s[j]=='+') b1[i]|=1<<j-1;
else if(s[j]=='-') b2[i]|=1<<j-1;
cin>>s+1;len=strlen(s+1);
for(int j=1;j<=len;j++)
if(s[j]=='+') f1[i]|=1<<j-1;
else if(s[j]=='-') f2[i]|=1<<j-1;
}
spfa();
if(dis[0]!=INF) printf("%d",dis[0]);
else printf("0");
}