CCF CSP 201412-5 货物调度

货物调度

在这里插入图片描述
在这里插入图片描述

题意

  在由n个节点组成的无向图中,AB边的权值C代表,从A到B运输每吨需要的费用。一些节点生产货物,一些节点接收货物(就像快递一样,一方发货一方收货),但是又存在区别,这里默认发货站点能够将货物在当日送达收货站点,但是虽然你可以送到我这里,真正来收获的人预订好是某个时间(周一到周日来计算)来取货,可能要过几天来取,这就出现了暂存费用,每个站点的暂存费用不一样,而且每个站点空间有限只能存v吨货物,题目要求所有货物送达费用和路途中暂存费用的总费用达到最少。

题解

  大致读懂题意,感觉应该和费用流有关系,出现了每个站点存储空间限定(相当于流量限制),每个站点每吨存储费用(相当于单位流量的费用),接下进一步思考如何建图:起点与终点,很明显是所有发货站点与所有收获站点,用一个超级源点与超级终点连接即可;为了很好体现以天为单位的存储流量与费用,将每个站点分成七份,每一天一份,从第一天转移到第二天,只需要将这两个点连起来赋予流量与费用即可,每个点这样处理一遍,这样就将时间加进去了;站点间运送:流量无限,费用为边权。最后跑一遍ZKW费用流即可,100分。O(n^2m)
如下做题草稿:
做题笔记

代码

#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false)
#define maxn 805
#define maxm 50005
#define INF 200000005
#define ll long long

struct ZKW
{
    int s, t, n;
    int cost;
    bool vis[maxn];
    int dist[maxn];
    //vis两个用处:spfa里的访问标记,増广时候的访问标记,dist是每个点的距离标号
    int nedge, p[maxm], c[maxm], cc[maxm], nex[maxm], head[maxn];
    //p[i]表示以某一点出发的编号为i的边对应点,c表示编号为i的边的流量,cc表示编号为i的边的费用
    void addedge(int x, int y, int z, int zz)//x->y 流量 费用
    {
        p[++nedge] = y, c[nedge] = z, cc[nedge] = zz, nex[nedge] = head[x], head[x] = nedge;
        p[++nedge] = x, c[nedge] = 0, cc[nedge] = -zz, nex[nedge] = head[y], head[y] = nedge;
    }

    void init(int n, int s, int t)//传入有多少个点,起点及终点
    {
        this->n = n, this->s = s, this->t = t;
        memset(nex, -1, sizeof nex);
        memset(head, -1, sizeof head);
        cost = 0, nedge = -1;
    }

    bool spfa(int s, int t)
    {
        memset(vis, 0, sizeof vis);
        for (int i = 0; i <= n; i++)dist[i] = INF;
        dist[t] = 0;
        vis[t] = 1;
        deque<int>q;
        q.push_back(t);
        while (!q.empty())
        {
            int now = q.front();
            q.pop_front();
            for (int k = head[now]; k>-1; k = nex[k])if (c[k ^ 1] && dist[p[k]]>dist[now] - cc[k])
                {
                    dist[p[k]] = dist[now] - cc[k];
                    if (!vis[p[k]])
                    {
                        vis[p[k]] = 1;
                        if (!q.empty() && dist[p[k]]<dist[q.front()])q.push_front(p[k]);
                        else q.push_back(p[k]);
                    }
                }
            vis[now] = 0;
        }
        return dist[s]<INF;
    }

    int dfs(int x, int low)
    {
        //这里就是进行増广了
        if (x == t)
        {
            vis[t] = 1;
            return low;
        }
        int used = 0, a;
        vis[x] = 1;
        //这边是不是和dinic很像啊
        for (int k = head[x]; k>-1; k = nex[k])if (!vis[p[k]] && c[k] && dist[x] - cc[k] == dist[p[k]])
            {
                //这个条件就表示这条边可以进行増广
                a = dfs(p[k], min(c[k], low - used));
                if (a)cost += a * cc[k], c[k] -= a, c[k ^ 1] += a, used += a;
                //累加答案,加流等操作都在这了
                if (used == low)break;
            }
        return used;
    }
    int costflow()
    {
        int flow = 0;
        while (spfa(s, t))
        {
            //判断起点终点是否连通,不连通说明满流,做完了退出
            vis[t] = 1;
            while (vis[t])
            {
                memset(vis, 0, sizeof vis);
                flow += dfs(s, INF);
                //一直増广直到走不到为止(这样也可以省时间哦)
            }
        }
        return flow;//这里返回的是最大流,费用的答案在cost里
    }
} G;

int main()
{
    int n,m;
    cin>>n>>m;
    int st=0,ed=n*7+2;
    G.init(7*n+5,st,ed);

    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=7;j++)
        {
            int x;
            cin>>x;
            G.addedge(st,(i-1)*7+j,x,0);
        }

        for(int j=1;j<=7;j++)
        {
            int x;
            cin>>x;
            G.addedge((i-1)*7+j,ed,x,0);
        }

        int v,w;
        cin>>v>>w;
        for(int j=1;j<=6;j++)
            G.addedge((i-1)*7+j,(i-1)*7+j+1,v,w);
        G.addedge((i-1)*7+7,(i-1)*7+1,v,w);
    }

    for(int i=0;i<m;i++)
    {
        int x,y,z;
        cin>>x>>y>>z;
        for(int i=1;i<=7;i++)
        {
            G.addedge((x-1)*7+i,(y-1)*7+i,INF,z);
            G.addedge((y-1)*7+i,(x-1)*7+i,INF,z);
        }
    }

    G.costflow();
    cout<<G.cost;
    return 0;
}

发布了41 篇原创文章 · 获赞 2 · 访问量 1221

猜你喜欢

转载自blog.csdn.net/qq_41418281/article/details/104007018