网络流强化-POJ2516

  k种货物分开求解最小费用最大流,主要减少了寻找最短路的时间。

  

#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxe 256000   //pay
#define maxv 5120    //pay
#define maxn 55    //pay
#define sc scanf
#define pt printf
#define rep(i,a,b)  for(int i=(a);i<(b);++i)
const int inf = 0x3f3f3f3f;
int fee,cg,sp,need;
int N,M,K ,s,t;
typedef struct ed{
    int v,nxt,cap,dis;
}ed;
ed e[maxe];
int nxt[maxe],tot,head[maxv],vis[maxv],d[maxv],bk[maxv];
int mp[maxn][maxn][maxn];
int mi(int a,int b) {return a<b?a:b;}
void add(int u,int v,int cap,int dis)
{
    e[tot].v=v;         e[tot].nxt=head[u];
    e[tot].dis=dis;     e[tot].cap=cap;
    head[u]=tot++;

    e[tot].v=u;         e[tot].nxt=head[v];
    e[tot].dis=-dis;    e[tot].cap=0;
    head[v]=tot++;
}
int spfa()
{
    queue<int> q;
    int u = s,v;
    q.push(u);
    while(!q.empty())
    {
        u = q.front(); q.pop();
        vis[u] = 0;
        for(int i = head[u];~i;i=e[i].nxt)
        {
            if(e[i].cap<1) continue;
            v = e[i].v;
            if(d[u]+e[i].dis<d[v])
            {
                bk[v]=i;
                d[v] = d[u]+e[i].dis;
                if(vis[v]==0)
                {
                    q.push(v);
                    vis[v]=1;
                }
            }
        }
    }
    return d[t]!=inf;
}

void init()
{
    tot=0;
    memset(head,-1,sizeof(head));   //pay
}
int cust_need[maxn][maxn];
int halt_prov[maxn][maxn];
//第一次改进:如果仓库这种东西的存量为0或者客户需求为0,他们之间不建立边 —— 居然RE了
int main()
{
    freopen("in.txt","r",stdin);
    d[0]=0; bk[0]=-1;
    while(1)
    {
        need = fee = sp = 0;
        sc("%d%d%d",&N,&M,&K); //pt("%d %d %d\n",N,M,K);
        if(N==0&&M==0&&K==0) break;
        s=0,t=1+N+M;
        int i,j,k;
        memset(mp,-1,sizeof(mp));
        for(i=0;i<N;++i)  for(j=1;j<=K;++j) sc("%d",&cust_need[i][j]),need+=cust_need[i][j];
        for(i=0;i<M;++i)  for(j=1;j<=K;++j) sc("%d",&halt_prov[i][j]);
        for(k=1;k<=K;++k)  for(i=0;i<N;++i) for(j=0;j<M;++j)
        {
            sc("%d",&mp[k][i][j]);
            if(halt_prov[j][k]==0||cust_need[i][k]==0) continue;
            add(j*K+k,K*M+i*K+k,mi(halt_prov[j][k],cust_need[i][k]),mp[k][i][j]);
        }
        for(k=1;k<=K;++k)
        {
            init();
            for(i=0;i<N;++i) if(cust_need[i][k]>0) add(1+M+i,t,cust_need[i][k],0);
            for(j=0;j<M;++j) if(halt_prov[j][k]>0) add(0,1+j,halt_prov[j][k],0);
            for(i=0;i<N;++i) for(j=0;j<M;++j)
            {
                if(halt_prov[j][k]==0||cust_need[i][k]==0) continue;
                add(1+j,1+M+i,mi(halt_prov[j][k],cust_need[i][k]),mp[k][i][j]);
            }
            while(1)
            {
                for(i=1;i<=t;++i) d[i]=inf,vis[i]=0;
                if(spfa()==0) break;
                int min_flow = inf;
                cg=bk[t];
                while(cg!=-1)
                {
                    min_flow = mi(min_flow,e[cg].cap);
                    cg=bk[e[cg^1].v];
                }
                sp+=min_flow;
                cg=bk[t];
                while(cg!=-1)
                {
                    e[cg].cap-=min_flow;
                    e[cg^1].cap+=min_flow;
                    fee+=e[cg].dis*min_flow;
                    cg=bk[e[cg^1].v];
                }
            }
        }
        if(sp==need)   pt("%d\n",fee); //  write(fee), pt("\n");
        else pt("-1\n");
    }

    return 0;
}

POJ 2516

原文地址:https://www.cnblogs.com/lighten-up-belief/p/11345934.html

时间: 2024-10-25 06:10:43

网络流强化-POJ2516的相关文章

网络流强化-HDU2732

第一次遇到加了“多余”的边会导致WA的——在我看来是很多余,见代码191行 之后会思考为什么,想出来再更. //http://www.renfei.org/blog/isap.html 带解释的 //https://www.cnblogs.com/bosswnx/p/10353301.html 形式和我的比较相近的 #include<cstdio> #include<cstring> #include<cmath> using namespace std; #defin

网络流强化-HDU 3338-上下界限制最大流

题意是: 一种特殊的数独游戏,白色的方格给我们填1-9的数,有些带数字的黑色方格,右上角的数字代表从他开始往右一直到边界或者另外一个黑格子,中间经过的白格子的数字之和要等于这个数字:左下角的也是一样的意思,只是作用对象成了它下方的白格子. 思路: 既然所有行的数字之和等于所有列的数字之和,那么我们可以将行方向(向右)的点作为与源点连接的点,列方向(向下)的点作为与汇点连接的点. 由于向右和向下的点可能在同一块方格里面,以及我们需要设置每个白格子的容量,所以我们需要拆点. 题目要求填1-9的数,所

网络流之费用流问题

费用流即最小费用最大流 先贴上粉书上的模板: struct Edge { int from,to,cap,flow,cost; Edge(int u,int v,int c,int f,int w): from(u),to(v),cap(c),flow(f),cost(w) {} }; int n,m; vector<Edge> edges; vector<int> G[maxn]; int inq[maxn]; int d[maxn]; int p[maxn]; int a[ma

hiho 第118周 网络流四&#183;最小路径覆盖

描述 国庆期间正是旅游和游玩的高峰期. 小Hi和小Ho的学习小组为了研究课题,决定趁此机会派出若干个调查团去沿途查看一下H市内各个景点的游客情况. H市一共有N个旅游景点(编号1..N),由M条单向游览路线连接.在一个景点游览完后,可以顺着游览线路前往下一个景点. 为了避免游客重复游览同一个景点,游览线路保证是没有环路的. 每一个调查团可以从任意一个景点出发,沿着计划好的游览线路依次调查,到达终点后再返回.每个景点只会有一个调查团经过,不会重复调查. 举个例子: 上图中一共派出了3个调查团: 1

JavaScript强化教程 - 六步实现贪食蛇

本文为H5EDU机构官方的HTML5培训教程,主要介绍贪食蛇JavaScript强化教程 1.首先创建div 并且给div加样式 <div id="pannel" style="width: 500px;height: 500px;z-index: 1;opacity: 0.5"></div> 给 <style...> 地图(div和表格).所有的块(蛇头,食物身体加样式) 2.创建地图     document.write(&q

POJ2584 T-Shirt Gumbo 二分图匹配(网络流)

1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 const int inf=0x3f3f3f3f; 6 const int sink=30; 7 8 struct Edge 9 { 10 int to; 11 int next; 12 int capacity; 13 14 void assign(int t,int n,int c) 15 { 16 to=t; next=n; ca

UVA 1306 - The K-League(网络流)

UVA 1306 - The K-League 题目链接 题意:n个球队,已经有一些胜负场,现在还有一些场次,你去分配胜负,问每支球队有没有可能获胜 思路:网络流公平分配模型,把场次当作任务,分配给人,然后先贪心,枚举每个人,让这些人能赢的都赢,剩下的去建图,每个源点连向比赛容量为场次,每个比赛连向2个球队,容量无限大,每个球队连向汇点,容量为每个的人的总和减去当前已经赢的,建完图跑一下最大流,然后判断源点流出的是否都满流即可 代码: #include <cstdio> #include &l

hdu 4975 A simple Gaussian elimination problem.(网络流,判断矩阵是否存在)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4975 Problem Description Dragon is studying math. One day, he drew a table with several rows and columns, randomly wrote numbers on each elements of the table. Then he counted the sum of each row and col

POJ训练计划3422_Kaka&#39;s Matrix Travels(网络流/费用流)

解题报告 题目传送门 题意: 从n×n的矩阵的左上角走到右下角,每次只能向右和向下走,走到一个格子上加上格子的数,可以走k次.问最大的和是多少. 思路: 建图:每个格子掰成两个点,分别叫"出点","入点", 入点到出点间连一个容量1,费用为格子数的边,以及一个容量∞,费用0的边. 同时,一个格子的"出点"向它右.下的格子的"入点"连边,容量∞,费用0. 源点向(0,0)的入点连一个容量K的边,(N-1,N-1)的出点向汇点连一