zoukankan      html  css  js  c++  java
  • [BZOJ2324][ZJOI2011][最小费用最大流]营救皮卡丘

    [Problem Description]
    皮卡丘被火箭队用邪恶的计谋抢走了!这三个坏家伙还给小智留下了赤果果的挑衅!为了皮卡丘,也为了正义,小智和他的朋友们义不容辞的踏上了营救皮卡丘的道路。
    火箭队一共同拥有N个据点,据点之间存在M条双向道路。据点分别从1到N标号。小智一行K人从真新镇出发,营救被困在N号据点的皮卡丘。为了方便起见,我们将真新镇视为0号据点,一開始K个人都在0号点。
    因为火箭队的重重布防,要想摧毁K号据点,必须依照顺序先摧毁1到K-1号据点,而且,假设K-1号据点没有被摧毁,因为防御的连锁性,小智一行不论什么一个人进入据点K,都会被发现,并产生严重后果。因此,在K-1号据点被摧毁之前,不论什么人是不可以经过K号据点的。
    为了简化问题,我们忽略战斗环节,小智一行不论什么一个人经过K号据点即觉得K号据点被摧毁。被摧毁的据点依旧是能够被经过的。
    K个人是能够分头行动的,仅仅要有不论什么一个人在K-1号据点被摧毁之后,经过K号据点,K号据点就被摧毁了。显然的,仅仅要N号据点被摧毁,皮卡丘就得救了。
    野外的道路是不安全的,因此小智一行希望在摧毁N号据点救出皮卡丘的同一时候,使得K个人所经过的道路的长度总和最少。
    请你帮助小智设计一个最佳的营救方案吧!
    [Algorithm]
    最小费用最大流
    [Analysis]
    题目有几个关键点:
    1.每个点都必须有人经过
    2.经过j点时,0~j-1必须都经过了才干够
    由此能够构造出一个网络流的模型。
    因为每一个节点的第一次訪问,必然是由小于它的节点完毕的,所以先用floyd预处理dis[k][i][j]表示i到j仅仅经过小于等于k的点的最短路。建图例如以下
    1.S->0 cap=k cost=0
    2.i->T cap=1 cost=0
    3.S->i+n cap=1 cost=0
    4.i+n->j cap=INF cost=dis[j][i][j]
    1是用来限制人数的,2则保证每一个点经过一次,因为第一次经过该点时流向了T消耗了流量,所以每一个点给予补充流量,即建图3。4则是从一个刚刚第一次经过的点继续訪问其他点。这样建图能够发现,每一个点的第一次訪问都被转化成了一条从S出发的流且没有交叉,这样能够随意调整訪问顺序,保证了j訪问之前0~j-1都已经訪问过
    [Pay Attention]
    因为floyd要用邻接矩阵,注意推断重边的情况取最小。
    还有要从这样的点至少经过一次的建模中吸取经验
    [Code]
    /**************************************************************
        Problem: 2324
        User: gaotianyu1350
        Language: C++
        Result: Accepted
        Time:392 ms
        Memory:7620 kb
    ****************************************************************/
     
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <cstdlib>
    #include <queue>
    #include <iostream>
    using namespace std;
     
    #define MAXN 350
    #define MAXM 300000
    #define INF  0x3f3f3f3f
     
    int point[MAXN], next[MAXM], v[MAXM], flow[MAXM], cap[MAXM], w[MAXM];
    int lastedge[MAXN], dis[MAXN];
    bool check[MAXN];
    int tot = -1;
     
    int n, m, people;
    int map[MAXN][MAXN];
     
    inline void init()
    {
        memset(map, 0x7f, sizeof(map));
        memset(point, -1, sizeof(point));
        memset(next, -1, sizeof(next));
        tot = -1;
    }
     
    inline void addedge(int x, int y, int theCap, int theDis)
    {
        tot++;
        next[tot] = point[x]; point[x] = tot; 
        v[tot] = y; flow[tot] = 0; cap[tot] = theCap; w[tot] = theDis;
        tot++;
        next[tot] = point[y]; point[y] = tot;
        v[tot] = x; flow[tot] = 0; cap[tot] = 0; w[tot] = - theDis;
    }
     
    inline int addflow(int s, int t)
    {
        int now = t;
        int ans = INF;
        while (now != s)
        {
            int temp = lastedge[now];
            ans = min(ans, cap[temp] - flow[temp]);
            now = v[lastedge[now] ^ 1];
        }
        now = t;
        while (now != s)
        {
            flow[lastedge[now]] += ans;
            flow[lastedge[now] ^ 1] -= ans;
            now = v[lastedge[now] ^ 1];
        }
        return ans;
    }
     
    bool spfa(int s, int t, int &maxflow, int &mincost)
    {
        queue<int> q;
        while (!q.empty()) q.pop();
        memset(dis, 0x7f, sizeof(dis));
        memset(check, 0, sizeof(check));
        dis[s] = 0; check[s] = true; q.push(s);
        while (!q.empty())
        {
            int now = q.front(); q.pop();
            check[now] = false;
            for (int temp = point[now]; temp != -1; temp = next[temp])
                if (flow[temp] < cap[temp] && dis[now] + w[temp] < dis[v[temp]])
                {
                    dis[v[temp]] = dis[now] + w[temp];
                    lastedge[v[temp]] = temp;
                    if (!check[v[temp]])
                        check[v[temp]] = true, q.push(v[temp]);
                }
        }
        if (dis[t] > INF) return false;
        int add = addflow(s, t);
        maxflow += add;
        mincost += add * dis[t];
        return true;
    }
     
    inline int solve(int s, int t)
    {
        int maxflow = 0, mincost = 0;
        while (spfa(s, t, maxflow, mincost));
        /*{
            int tiaoshi = 1;
            tiaoshi++;
        }*/
        //printf("mflow :%d
    ", maxflow);
        return mincost;
    }
     
    inline void build(int start, int end)
    {
        addedge(start, 0, people, 0);
        for (int i = 1; i <= n; i++)
        {
            addedge(i, end, 1, 0);
            addedge(start, i + n, 1, 0);
            //addedge(i, i + n, INF, 0);
        }
        for (int k = 0; k <= n; k++)
        for (int i = 0; i <= n; i++)
        for (int j = 0; j <= n; j++)
            if (i != j)
            {
                if (map[i][k] < INF && map[k][j] < INF)
                    map[i][j] = min(map[i][j], map[i][k] + map[k][j]);
                if (k == j && i < j && map[i][j] < INF)
                    addedge(i == 0 ? 0 : i + n, j, INF, map[i][j]);       
            }   
    }
     
    int main()
    {
        //freopen("input.txt", "r", stdin);
        init();
        scanf("%d%d%d", &n, &m, &people);
        for (int i = 1; i <= m; i++)
        {
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            if (z < map[x][y])
                map[x][y] = map[y][x] = z;
        }
        build(2 * n + 1, 2 * n + 2);
        printf("%d
    ", solve(2 * n + 1, 2 * n + 2));
    }


  • 相关阅读:
    python的三大控制机构(ifelse、for、while)
    python 异常处理
    《精通javascript》笔记
    IE6与!important
    point
    js 自制滚动条
    《Head first 设计模式》读书笔记
    Asp.net Webform 数据源绑定控件的扩展(懒人的办法):DropDownList
    Asp.net Binarysoft.Library 数据库通用操作层(Binarysoft.Library.Data)
    Asp.net Webform 从项目的数据库设计说起,什么是一个好的数据库设计。
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/3845444.html
Copyright © 2011-2022 走看看