http://poj.org/problem?id=2516
题意:N个批发商,M个供应商,K种商品,每个批发商每种商品都需要一定的数量,每个供应商每种商品都提供一定的数量。
每个供应商向每个批发商运送某种单位数量的商品
KM 思路:每种商品 需要a个,那x边就有a个点,该种商品供应有b个,那y边就有b个点,
权值为,运费。。。说的有点乱。就是我看了别人的这种思路之后,输入还是没搞定。。。这输入也挺有技巧的,我是
这样觉得 匈牙利算法时间复杂度O(ne) ,KM每找到一条增广路径要顶标调整,复杂度O(ne^2) 不知道我这个KM的复杂度
是不是那么小
代码(KM):
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#define inf 1<<30
#define Max(a,b)a>b?a:b
#define Min(a,b)a<b?a:b
#define nMAX 155
using namespace std;
int map[nMAX][nMAX],link[nMAX],lx[nMAX],ly[nMAX];
bool vx[nMAX],vy[nMAX];
int n,m;
bool dfs(int u)
{
int j;
vx[u]=1;
for(j=1;j<=m;j++)
if(!vy[j]&&map[u][j]==lx[u]+ly[j])//!!!map[u][j]==lx[u]+ly[j]
{
vy[j]=1;
if(!link[j]||dfs(link[j]))
{
link[j]=u;
return true;
}
}
return false;
}
int KM()
{
int i,j,k;
for(i=1;i<=n;i++)
{ lx[i]=-inf;
for(j=1;j<=m;j++)
lx[i]=Max(lx[i],map[i][j]);//每个map[i][j]都已初始化
}
memset(ly,0,sizeof(ly));
memset(link,0,sizeof(link));
for(i=1;i<=n;i++)
{
while(1)
{
memset(vx,0,sizeof(vx));
memset(vy,0,sizeof(vy));
if(dfs(i))break;
//修改 lx ly
int MIN=inf;
for(j=1;j<=n;j++)
if(vx[j])
for(k=1;k<=m;k++)
if(!vy[k])
MIN=Min(MIN,lx[j]+ly[k]-map[j][k]);
for(j=1;j<=n;j++)if(vx[j])lx[j]-=MIN;//lx[j]--;错错错
for(j=1;j<=m;j++)if(vy[j])ly[j]+=MIN;
}
}
int ANS=0;
for(i=1;i<=m;i++)
if(link[i]) ANS+=map[link[i]][i];
return ANS;
}
int main()
{
int cn[55][nMAX],cm[55][nMAX],com1[55],com2[55],f[55][55];
int N,M,K;
int i,j,h,cnt;
while(scanf("%d%d%d",&N,&M,&K))
{
if(N==0&&M==0&&K==0)break;
memset(com1,0,sizeof(com1));
memset(com2,0,sizeof(com2));
// memset(cn,0,sizeof(cn));
// memset(cm,0,sizeof(cm));
for(i=1;i<=N;i++)
for(j=1;j<=K;j++)
{
scanf("%d",&cnt);
while(cnt--)
cn[j][++com1[j]]=i; //第com1[j]件第j中商品,第i个shop需要
}
for(i=1;i<=M;i++)
for(j=1;j<=K;j++)
{
scanf("%d",&cnt);
while(cnt--)
cm[j][++com2[j]]=i; //同理
}
bool flag=1;
int ans=0;
for(h=1;h<=K;h++)
{
for(i=1;i<=N;i++)
for(j=1;j<=M;j++)
scanf("%d",&f[i][j]);
if(com1[h]>com2[h])
{
flag=0;
continue;
}
memset(map,0,sizeof(map));
for(i=1;i<=com1[h];i++)
for(j=1;j<=com2[h];j++)
{
map[i][j]=-f[cn[h][i]][cm[h][j]];
}
n=com1[h];
m=com2[h];
ans-=KM();
}
if(!flag)printf("%d\n",-1);
else printf("%d\n",ans);
}
return 0;
}
最小费用最大流
思路:因为涉及到K种商品,所以 考虑到 N*K个需求者,M*K个供应者,就是一种需求者只需求一种产品,一种供应者只提供一种产品;需求第i 个产品的需求者 向提供第i的供应真连线,cap=inf,cost=运费,源点到需求者连线 cap=需求量,cost=0 ,供应者到汇点连线,cap=提供量,cost=0。。。就是基于把每个需求者分成K个需求者,把每个供应者分成K个供应者。。。结果TLE,囧 时间复杂度 最坏有2500+2500+2个点,(2500*50+2500*2)*2=26*10^4 条边 ,费用流的时间复杂度是O(2*M*C)吧?!好像是,m是边,C是流量3 , O(2*M)是spfa的复杂度, 最后用时 26*10^4*2*2500*3=3.9*10^9 怪不得超时
然后网上是单独的算出每种产品的费用,因为每种产品是相互独立的,然后加起来,那时间复杂度是多少呢?每一种产品 最坏情况用50+50+2个点,(50*50+50*2)*2=5200条边 O(2*m*c)=1.56*10^6 ,50种产品就有 50*1.56*10^6=7.8*10^7
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#define nMAX 110
#define mMAX 6000
#define inf 1<<26
using namespace std;
int s,n;
int head[nMAX],s_edge,ans,dis[nMAX],pre[nMAX],qu[nMAX],num;
int need[55][55],provide[55][55],cntn[55],cntp[55];
bool vs[nMAX];
struct Edge
{
int u,v,cap,cost,nxt;
}edge[mMAX];
void addedge(int u,int v,int cap,int cost)
{
s_edge++;
edge[s_edge].v=v;
edge[s_edge].cap=cap;
edge[s_edge].cost=cost;
edge[s_edge].nxt=head[u];
head[u]=s_edge;
s_edge++;
edge[s_edge].v=u;
edge[s_edge].cap=0;
edge[s_edge].cost=-cost;
edge[s_edge].nxt=head[v];
head[v]=s_edge;
}
bool spfa()
{
int i,beg,tail;
for(i=0;i<=n;i++)
{
dis[i]=inf;
vs[i]=0;
}
beg=0,tail=1;
dis[s]=0;
vs[s]=1;
qu[0]=s;
while(beg!=tail)
{
int u=qu[beg++];
for(int e=head[u];e;e=edge[e].nxt)
{
int v=edge[e].v;
if(edge[e].cap&&dis[v]-dis[u]>edge[e].cost)
{
dis[v]=dis[u]+edge[e].cost;
pre[v]=e;
if(!vs[v])
{
vs[v]=1;
qu[tail++]=v;
if(tail==nMAX)tail=0;
}
}
}
vs[u]=0;
if(beg==nMAX)beg=0;
}
if(dis[n]!=inf)return 1;
return 0;
}
void end()
{
int u,p;
int MIN=inf;
for(u=n;u!=s;u=edge[p^1].v)
{
p=pre[u];
MIN=MIN<edge[p].cap?MIN:edge[p].cap;
}
num+=MIN;
for(u=n;u!=s;u=edge[p^1].v)
{
p=pre[u];
edge[p].cap-=MIN;
edge[p^1].cap+=MIN;
ans+=(edge[p].cost*MIN);
}
}
int main()
{
int N,M,K,i,j,f,w;
while(~scanf("%d%d%d",&N,&M,&K))
{
if(N==0&&M==0&&K==0)break;
memset(cntn,0,sizeof(cntn));
memset(cntp,0,sizeof(cntp));
for(i=1;i<=N;i++)
for(j=1;j<=K;j++)
{
scanf("%d",&need[i][j]);
cntn[j]+=need[i][j];
}
for(i=1;i<=M;i++)
for(j=1;j<=K;j++)
{
scanf("%d",&provide[i][j]);
cntp[j]+=provide[i][j];
}
bool fg=1;
ans=0;
for(i=1;i<=K;i++)
{
s_edge=1;
memset(head,0,sizeof(head));
s=0,n=N+M+1;
for(j=1;j<=N;j++)
for(f=1;f<=M;f++)
{
scanf("%d",&w);
addedge(j,N+f,inf,w);
}
if(cntp[i]<cntn[i]){fg=0;continue;}
for(j=1;j<=N;j++)
addedge(s,j,need[j][i],0);
for(j=1;j<=M;j++)
addedge(N+j,n,provide[j][i],0);
num=0;
if(fg)
while(spfa())
{
end();
}
if(num<cntn[i])fg=0;//不能break啊,数据读不完就WA!!!^ ^
}
if(fg)
printf("%d\n",ans);
else
printf("-1\n");
}
return 0;
}