POJ2516 Minimum Cost 最大流最小费用典型题目
2011-09-19 22:40
281 查看
刚接触spfa算法。
我的理解是spfa算法实质是bellman算法的改进版,可以处理负值,这是和dij的本质区别,也是这里不能用dij的原因。
spfa算法的队列的大小一定要注意!开小了悲情无限。
而最大流最小费用的思路说简单了就是最大流的实现时,以前没有最小费用这个约束的时候,我们很随意的可以直接用bfs来搜索增广路径来解最大流。
但此时有最小费用这个约束。我们用最短路来搜索增广路径。
这样来求得的最大流则满足题意。
#include<iostream>
using namespace std;
int n,m,k;
const int inf=9999999;
const int N=111;
int shop
;
int storage
;
int mat
;
int cost
;
int ans;
bool visit
;
int que[N*N],pre
,dis
;//que的大小设定不是简单的N,之前在广搜的时候习惯是N,上次一题就是直接写N,就一直TLE,今天才意识到,泪流满面。
bool spfa()
{
int head=1,tail=1;
for(int i=0;i<=n+m+1;i++)
{
dis[i]=inf;
visit[i]=false;
}
dis[0]=0;
que[tail++]=0;
visit[0]=true;
while(head<tail)
{
int now=que[head++];
for(int i=0;i<=n+m+1;i++)
if(mat[now][i]>0&&dis[i]>dis[now]+cost[now][i])
{
dis[i]=dis[now]+cost[now][i];
pre[i]=now;
if(!visit[i])
{
visit[i]=true;
que[tail++]=i;
//if
}
}
visit[now]=false;
}
if(dis[n+m+1]==inf)
return false;
return true;
}
int main()
{
while(scanf("%d%d%d",&n,&m,&k),n!=0||m!=0||k!=0)
{
ans=0;
int need
;
memset(need,0,sizeof(need));
memset(shop,0,sizeof(shop));
for(int i=1;i<=n;i++)
for(int j=1;j<=k;j++)
{
scanf("%d",&shop[i][j]);
need[j]+=shop[i][j];
}
int supply
;
memset(supply,0,sizeof(supply));
memset(storage,0,sizeof(storage));
for(int i=1;i<=m;i++)
for(int j=1;j<=k;j++)
{
scanf("%d",&storage[i][j]);
supply[j]+=storage[i][j];
}
bool flag=false;
for(int i=1;i<=k;i++)
{
if(supply[i]<need[i])
{
flag=true;
break;
}
}
for(int t=1;t<=k;t++)
{
memset(mat,0,sizeof(mat));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&cost[j][m+i]);
cost[m+i][j]=-cost[j][m+i];//这就是用spfa而不能用dij的原因
mat[j][m+i]=inf;
}
if(flag)
continue;
for(int i=1;i<=m;i++)
{
mat[0][i]=storage[i][t];
cost[0][i]=cost[i][0]=0;
}
for(int i=1;i<=n;i++)
{
mat[m+i][n+m+1]=shop[i][t];
cost[m+i][n+m+1]=cost[n+m+1][m+i]=0;
}
while(spfa())
{
int min=inf;
for(int i=m+n+1;i!=0;i=pre[i])
{
min=(min<mat[pre[i]][i]?min:mat[pre[i]][i]);
}
for(int i=n+m+1;i!=0;i=pre[i])
{
mat[pre[i]][i]-=min;
mat[i][pre[i]]+=min;
ans+=cost[pre[i]][i]*min;
}
}
}
if(flag)
printf("-1\n");
else
printf("%d\n",ans);
}
return 0;
}
我的理解是spfa算法实质是bellman算法的改进版,可以处理负值,这是和dij的本质区别,也是这里不能用dij的原因。
spfa算法的队列的大小一定要注意!开小了悲情无限。
而最大流最小费用的思路说简单了就是最大流的实现时,以前没有最小费用这个约束的时候,我们很随意的可以直接用bfs来搜索增广路径来解最大流。
但此时有最小费用这个约束。我们用最短路来搜索增广路径。
这样来求得的最大流则满足题意。
#include<iostream>
using namespace std;
int n,m,k;
const int inf=9999999;
const int N=111;
int shop
;
int storage
;
int mat
;
int cost
;
int ans;
bool visit
;
int que[N*N],pre
,dis
;//que的大小设定不是简单的N,之前在广搜的时候习惯是N,上次一题就是直接写N,就一直TLE,今天才意识到,泪流满面。
bool spfa()
{
int head=1,tail=1;
for(int i=0;i<=n+m+1;i++)
{
dis[i]=inf;
visit[i]=false;
}
dis[0]=0;
que[tail++]=0;
visit[0]=true;
while(head<tail)
{
int now=que[head++];
for(int i=0;i<=n+m+1;i++)
if(mat[now][i]>0&&dis[i]>dis[now]+cost[now][i])
{
dis[i]=dis[now]+cost[now][i];
pre[i]=now;
if(!visit[i])
{
visit[i]=true;
que[tail++]=i;
//if
}
}
visit[now]=false;
}
if(dis[n+m+1]==inf)
return false;
return true;
}
int main()
{
while(scanf("%d%d%d",&n,&m,&k),n!=0||m!=0||k!=0)
{
ans=0;
int need
;
memset(need,0,sizeof(need));
memset(shop,0,sizeof(shop));
for(int i=1;i<=n;i++)
for(int j=1;j<=k;j++)
{
scanf("%d",&shop[i][j]);
need[j]+=shop[i][j];
}
int supply
;
memset(supply,0,sizeof(supply));
memset(storage,0,sizeof(storage));
for(int i=1;i<=m;i++)
for(int j=1;j<=k;j++)
{
scanf("%d",&storage[i][j]);
supply[j]+=storage[i][j];
}
bool flag=false;
for(int i=1;i<=k;i++)
{
if(supply[i]<need[i])
{
flag=true;
break;
}
}
for(int t=1;t<=k;t++)
{
memset(mat,0,sizeof(mat));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&cost[j][m+i]);
cost[m+i][j]=-cost[j][m+i];//这就是用spfa而不能用dij的原因
mat[j][m+i]=inf;
}
if(flag)
continue;
for(int i=1;i<=m;i++)
{
mat[0][i]=storage[i][t];
cost[0][i]=cost[i][0]=0;
}
for(int i=1;i<=n;i++)
{
mat[m+i][n+m+1]=shop[i][t];
cost[m+i][n+m+1]=cost[n+m+1][m+i]=0;
}
while(spfa())
{
int min=inf;
for(int i=m+n+1;i!=0;i=pre[i])
{
min=(min<mat[pre[i]][i]?min:mat[pre[i]][i]);
}
for(int i=n+m+1;i!=0;i=pre[i])
{
mat[pre[i]][i]-=min;
mat[i][pre[i]]+=min;
ans+=cost[pre[i]][i]*min;
}
}
}
if(flag)
printf("-1\n");
else
printf("%d\n",ans);
}
return 0;
}
相关文章推荐
- POJ2516 Minimum Cost 最大流最小费用典型题目
- hdu 6118 度度熊的交易计划 (最小费用最大流
- 线性规划与单纯型法/最小(大)费用最大流题目泛做
- ZOJ3362 Beer Problem,有重边的最大流最小费用
- 011-题目:输入两个正整数m和n,求其最大公约数和最小公倍数。
- 动态规划--二维费用背包--最大最小价值--hdu4968 Improving the GPA
- hdu 4067 最小费用最大流
- 最大流,最小割,二分匹配,题目列表
- hdu 6118 度度熊的交易计划 (最小费用最大流
- 题目:输入两个正整数m和n,求其最大公约数和最小公倍数。(C语言)
- POJ-3422-最大流最小费用
- 题目1053:互换最大最小数
- 【程序6】 题目:输入两个正整数m和n,求其最大公约数和最小公倍数。
- poj 2516 Minimum Cost 【最小费用最大流】【求解K种物品的最小费用,独立求解累加每个结果】
- 【程序35】 ArrayChange.java 题目:输入数组,最大的与第一个元素交换,最小的与最后一个元素交换,输出数组。
- SSL P1643 最小乘车费用 题目
- hdu 6118 度度熊的交易计划 (最小费用最大流
- HDU 4859 最大流最小割经典题目
- Minimum Cost (最小费用)
- poj2516Minimum Cost最小费用最大流