//#if 0
#include <map>
#include <queue>
#include <math.h>
#include <string>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <queue>
#include <vector>
#include <set>
using namespace std;
#define ull unsigned long long
#define ll long long
#define cls(x) memset(x,0,sizeof(x))
#define clslow(x) memset(x,-1,sizeof(x))
const int maxn=1e5+10;
const int INF=0x3f3f3f3f;
int head[10000],cnt,n,m,dis[10000],vis[10000],pre[10000];
struct edg
{
int di,ai,v,nex,f,c,u;
edg(){}
edg(int di,int ai,int v,int nex,int f,int c):di(di),ai(ai),v(v),nex(nex),
f(f),c(c){}
}l[10000];
void addline(int u,int v,int di,int ai,int f,int c)//链式前向星存图
{
l[cnt].di=di;
l[cnt].ai=ai;
l[cnt].v=v;
l[cnt].u=u;
l[cnt].c=c;
l[cnt].f=f;
l[cnt].nex=head[u];
head[u]=cnt++;
l[cnt].di=-di;//反向边一起存了,花费是负数,起点终点交换,容量设置为1,流量为0
l[cnt].ai=ai;
l[cnt].u=v;
l[cnt].v=u;
l[cnt].f=0;
l[cnt].c=0;
l[cnt].nex=head[v];
head[v]=cnt++;
}
int spfa(int s,int t)//稍微增加一点判断的spfa
{
memset(dis,INF,sizeof(dis));
memset(pre,-1,sizeof(pre));
memset(vis,0,sizeof(vis));
queue<int>q;
dis[s]=0;
vis[s]=1;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for( int i=head[u] ; i!=-1 ; i=l[i].nex ){
if(l[i].c > l[i].f && l[i].di+dis[l[i].u] < dis[l[i].v])
{//判断容量大于当前流量,并且是可以松弛的边,才进行松弛;
//用于防止未被加入网络的边先行被选为最短路;
dis[l[i].v]=l[i].di+dis[l[i].u];
pre[l[i].v]=i;//用于找最短路路径的数组,pre【i】存放的就是到达i
//点,上一条经过的是第i条路,这个i针对的是存放线段的数组l,即l[i];
if(vis[l[i].v]==0){
q.push(l[i].v);
vis[l[i].v]=1;
}
}
}
}
// for(int i=0;i<=n+1;i++){
// cout<<dis[i]<<" ";
// }cout<<endl;
if(dis[t]==INF)return 0;//当各个重要通道流量满了,找不到通往汇点的路,返回0
else return 1;//从而使下方的循环退出
}
//void ou()
//{
// cout<<"---------------------------"<<endl;
// for(int i=0;i<cnt;i++){
// cout<<l[i].di<<" "<<l[i].f<<endl;
// }
//}
int min_cost(int s,int t,int &cost)
{
int f=0;//最大流量先设置为0
cost=0;//最小花费也先设置为0
while(spfa(s,t))
{
int Min=INF;//这个Min用来找刚才最短路上(容量-流量)的最小值,这样
//刚才找到的最短路,每条路都加上这个最小值,也不可能超过每条路的容量;
for(int i=pre[t];i!=-1;i=pre[l[i].u])
{//前向星式的查找路径;
// cout<<l[i].u<<" "<<l[i].v<<" "<<l[i].c<<" "<<l[i].f<<endl;
Min=min(l[i].c-l[i].f,Min);
}
for(int i=pre[t];i!=-1;i=pre[l[i].u])
{
l[i].f+=Min;//路径被走过,则正向的流量加上Min
l[i^1].f-=Min;//反向的流量减少Min,因为反向的流量和容量都是0,减少
//后流量就是负数了,相当于加入的网络,下次spfa操作,其可能会被选为最短路
//因为加边操作的时候,正向反向边都是一起加的,所以i^1就是反向边;
//^异或操作太骚了,存边的时候是01,23,34。。。。一对一对,4^1就是3
//3^1就是4了
cost+=l[i].di;
}
f+=Min;
}
return f;
}
int main()
{
// freopen("in1.txt", "r", stdin);
// freopen("out1.txt", "w", stdout);
int cas=1;
while(~scanf("%d%d",&n,&m))
{
memset(head,-1,sizeof(head));
cnt=0;
int u,v,di,ai;
while(m--){
scanf("%d%d%d%d",&u,&v,&di,&ai);
addline(u,v,di,ai,0,1);
addline(u,v,di+ai,ai,0,1);
}
int ans=0;
addline(0,1,0,0,0,2);//建立源点
addline(n,n+1,0,0,0,2);//建立汇点
min_cost(0,n+1,ans);
printf("Case %d: %d\n",cas++,ans);
}
return 0;
}
//#endif
最小花费最大流模板csu 1506
最新推荐文章于 2019-05-08 20:22:32 发布