P2457 [SDOI2006]仓库管理员的烦恼 (费用流)
每个仓库一种货物用流量限制。
然后代价就是费用。
源点连货物,汇点连仓库。
货物仓库连 把货物i 放到仓库j的代价就是
然后跑MCMF即可。
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=305,M=5e4+5,inf=0x3f3f3f3f,mod=1e9+7;
const int hashmod[4] = {402653189,805306457,1610612741,998244353};
void Print(int *a,int n){
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\n",a[n]);
}
template <typename T> //x=max(x,y) x=min(x,y)
void cmx(T &x,T y){
if(x<y) x=y;
}
template <typename T>
void cmn(T &x,T y){
if(x>y) x=y;
}
int cnt=1,h[N],flow[N],dis[N],vis[N],n,m,st,ed;
ll mc,mf;
int id(int x,int y){
return (x-1)*n+y;
}
queue<int>q;
struct edge{
int to,nt,f,w;//f:flow ,w:cost
}e[M];
struct Pre{
int i,u;
}pre[N];//记录前驱结点和边的信息,便于更新残余网络,建立反边.(反悔和贪心的思想)
void add(int u,int v,int f,int w){
e[++cnt]={v,h[u],f,w},h[u]=cnt;
e[++cnt]={u,h[v],0,-w},h[v]=cnt;
}
bool spfa(){// 跑spfa
mst(dis,0x3f),mst(flow,0x3f),mst(vis,0); //初始化.
q.push(st),vis[st]=1,dis[st]=0,pre[ed].u=-1;//预处理
while(!q.empty()){
int u=q.front();q.pop();vis[u]=0;
for(int i=h[u];i;i=e[i].nt){
int v=e[i].to,f=e[i].f,w=e[i].w;
if(f>0&&dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
pre[v].u=u,pre[v].i=i;
flow[v]=min(flow[u],f);
if(!vis[v]) vis[v]=1,q.push(v);
}
}
}
return pre[ed].u!=-1;
}
void MCMF(){ //MIncost Maxflow
while(spfa()){
int u=ed,x=flow[ed];
mf+=x;
mc+=x*dis[u];
while(u!=st){
e[pre[u].i].f-=x;
e[pre[u].i^1].f+=x;
u=pre[u].u;
}
}
}
int sum[N];
int v[N][N];
int main(){
scanf("%d",&n);
rep(i,1,n){
rep(j,1,n){
scanf("%d",&v[i][j]);
sum[j]+=v[i][j];
}
}
st = 0,ed = 2*n+1;
rep(i,1,n) add(st,i,1,0),add(i+n,ed,1,0);
rep(i,1,n)
rep(j,1,n){
add(i,j+n,1,sum[i]-v[j][i]);
}
MCMF();
printf("%lld\n",mc);
return 0;
}