zoukankan      html  css  js  c++  java
  • POJ 2175 Evacuation Plan

    POJ_2175

        据说这个题目裸着做费用流会超时,不过实际上看完这个题目还是不难发现更好的思路的,因为题目又没要求要最优解,而是得到一个更优的解,那么如果在原图中能够找到一个总费用为负的回路的话,那么沿这个回路流量增加1就能够在不改变原始总流量的基础上使总费用变得更低,于是我们只要试图去找这样一个负圈就可以了。

        如果用的SPFA的话,在一个点入队次数大于顶点数时就可以判断有负圈存在了,但这时刚刚入队的这个点却未必是负圈上的,但我们可以记录下来每个点被更新的前一个点,沿这个路径不停地回溯去找,直到发现找到的这个点在之间已经遇到过了,那么找到的这个点就一定是某个负圈上的点了。最后以这个点为基础,回溯找到整个负圈并更新流量即可。

        如果用Bellman-Ford的话,找负圈上的点就要更加纠结一些了……

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #define MAXD 210
    #define MAXM 20410
    #define INF 0x3f3f3f3f
    int N, M, first[MAXD], e, next[MAXM], v[MAXM], flow[MAXM], cost[MAXM];
    int dis[MAXD], pre[MAXD], vis[MAXD], sum[MAXD];
    struct Point
    {
        int x, y, z;
    }p[MAXD];
    int Dis(int i, int j)
    {
        return abs(p[i].x - p[j].x) + abs(p[i].y - p[j].y) + 1;
    }
    void add(int x, int y, int f, int c)
    {
        v[e] = y, flow[e] = f, cost[e] = c;
        next[e] = first[x], first[x] = e ++;    
    }
    void init()
    {
        int i, j, x, y, z;
        memset(first, -1, sizeof(first[0]) * (N + M + 1)), e = 0;
        for(i = 0; i < N + M; i ++) scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].z);
        memset(sum, 0, sizeof(sum[0]) * M);
        for(i = 0; i < N; i ++)
            for(j = 0; j < M; j ++)
            {
                scanf("%d", &x), sum[j] += x;
                add(i, N + j, INF - x, Dis(i, N + j)), add(N + j, i, x, -Dis(i, N + j));
            }
        for(i = 0; i < M; i ++)
            add(N + i, N + M, p[N + i].z - sum[i], 0), add(N + M, N + i, sum[i], 0);
    }
    int dfs(int cur, int &x)
    {
        int i = pre[cur];
        if(i == -1 || vis[cur] == 1) return 0;
        if(vis[cur] == -1)
        {
            x = cur;
            return 1;    
        }
        vis[cur] = -1;
        if(dfs(v[i ^ 1], x)) return 1;
        vis[cur] = 1;
        return 0;
    }
    void print()
    {
        int i, j, x;
        memset(vis, 0, sizeof(vis[0]) * (N + M + 1));
        for(i = 0; i <= N + M; i ++) if(!vis[i] && dfs(i, x)) break;
        for(i = pre[x]; ; i = pre[v[i ^ 1]])
        {
            flow[i] -= 1, flow[i ^ 1] += 1;
            if(v[i ^ 1] == x) break;
        }
        printf("SUBOPTIMAL\n");
        for(i = 0; i < N; i ++)
        {
            printf("%d", flow[i * M * 2 + 1]);
            for(j = 1; j < M; j ++) printf(" %d", flow[(i * M + j) * 2 + 1]);
            printf("\n");
        }
    }
    void solve()
    {
        int i, j, flag;
        memset(dis, 0, sizeof(dis[0]) * (N + M + 1));
        memset(pre, -1, sizeof(pre[0]) * (N + M + 1));
        for(i = 0; i <= N + M; i ++)
        {
            flag = 0;
            for(j = 0; j < e; j ++)
                if(flow[j] && dis[v[j]] > dis[v[j ^ 1]] + cost[j])
                    dis[v[j]] = dis[v[j ^ 1]] + cost[j], pre[v[j]] = j, flag = 1;
            if(flag == 0)
                break;    
        }
        if(i > N + M)
            print();
        else
            printf("OPTIMAL\n");
    }
    int main()
    {
        while(scanf("%d%d", &N, &M) == 2)
        {
            init();
            solve();    
        }
        return 0;    
    }
  • 相关阅读:
    Kafka 1.0.0集群安装
    java实现以docx格式导出
    基于java处理.docx格式的word合并
    基于java 合并.doc和docx格式的Word文件
    Docker版本Jenkins的使用
    Codeforces 1243 D 0-1 MST
    Public model for matrix
    Codeforces 1220 E Tourism
    Codeforces 1221 G Graph And Numbers
    Codeforces 1221 F Choose a Square
  • 原文地址:https://www.cnblogs.com/staginner/p/2647946.html
Copyright © 2011-2022 走看看