zoukankan      html  css  js  c++  java
  • POJ 2455 Secret Milking Machine (二分+无向图最大流)

    题意】n个点的一个无向图,在保证存在T条从1到n的不重复路径(任意一条边都不能重复)的前提下,要使得这t条路上经过的最长路径最短。 之所以把“经过的最长路径最短”划个重点是因为前面刚做了POJ2112那种求最长路径长度和最短的题,不要弄混了。在那道题中因为需要限制的是路径长度和,所以需要Floyd预处理路径,然后拆点变二分图防止间接流量边。然而这道题我们却不需要拆点了,直接建图即可。(类似最短路径和最小生成树的区别) 【建图】建一个源点连一条T流量的有向边到1节点;建一个汇点从n节点连一条T流量的有向边;其他边根据路径直接连一条无向边即可。 【无向边处理】在平常有向边的网络流加边时,我们都是加一条x流量的边再加一条0流量的反向边,那里反向边的作用的可以让程序自动修正流量路线。那么在加无向边时我们只要把反向边的流量也设为x即可,并且也不会失去修正的作用。 PS:有些人是像通常一样拆成两条相反边,并且还过了。但我觉得在网络流中这是不可行的,因为这样就改变了边流量的限制了。比如这道题中这样做,这条边明显不是只能走1次了吧。(2013.7.20:今天做了道拆点的题,发现如果是拆点的话这样也是可行的……>.<)  
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #define MID(x,y) ((x+y)/2)
    #define mem(a,b) memset(a,b,sizeof(a))
    using namespace std;
    const int MAXV = 205;
    const int MAXE = 80005;
    const int oo = 0x3fffffff;
    struct node{
        int u, v, flow;
        int opp;
        int next;
    };
    struct Dinic{
        node arc[MAXE];
        int vn, en, head[MAXV];     //vn点个数(包括源点汇点),en边个数
        int cur[MAXV];              //当前弧
        int q[MAXV];                //bfs建层次图时的队列
        int path[MAXE], top;        //存dfs当前最短路径的栈
        int dep[MAXV];              //各节点层次
        void init(int n){
            vn = n;
            en = 0;
            mem(head, -1);
        }
        void insert_flow(int u, int v, int flow){
            arc[en].u = u;
            arc[en].v = v;
            arc[en].flow = flow;
            arc[en].opp = en + 1;
            arc[en].next = head[u];
            head[u] = en ++;
    
            arc[en].u = v;
            arc[en].v = u;
            arc[en].flow = flow;       //反向弧
            arc[en].opp = en - 1;
            arc[en].next = head[v];
            head[v] = en ++;
        }
        bool bfs(int s, int t){
            mem(dep, -1);
            int lq = 0, rq = 1;
            dep[s] = 0;
            q[lq] = s;
            while(lq < rq){
                int u = q[lq ++];
                if (u == t){
                    return true;
                }
                for (int i = head[u]; i != -1; i = arc[i].next){
                    int v = arc[i].v;
                    if (dep[v] == -1 && arc[i].flow > 0){
                        dep[v] = dep[u] + 1;
                        q[rq ++] = v;
                    }
                }
            }
            return false;
        }
        int solve(int s, int t){
            int maxflow = 0;
            while(bfs(s, t)){
                int i, j;
                for (i = 1; i <= vn; i ++)  cur[i] = head[i];
                for (i = s, top = 0;;){
                    if (i == t){
                        int mink;
                        int minflow = 0x3fffffff;
                        for (int k = 0; k < top; k ++)
                            if (minflow > arc[path[k]].flow){
                                minflow = arc[path[k]].flow;
                                mink = k;
                            }
                        for (int k = 0; k < top; k ++)
                            arc[path[k]].flow -= minflow, arc[arc[path[k]].opp].flow += minflow;
                        maxflow += minflow;
                        top = mink;		//arc[mink]这条边流量变为0, 则直接回溯到该边的起点即可(这条边将不再包含在增广路内).
                        i = arc[path[top]].u;
                    }
                    for (j = cur[i]; j != -1; cur[i] = j = arc[j].next){
                        int v = arc[j].v;
                        if (arc[j].flow && dep[v] == dep[i] + 1)
                            break;
                    }
                    if (j != -1){
                        path[top ++] = j;
                        i = arc[j].v;
                    }
                    else{
                        if (top == 0)   break;
                        dep[i] = -1;
                        i = arc[path[-- top]].u;
                    }
                }
            }
            return maxflow;
        }
    }dinic;
    struct Path{
        int u, v, w;
    }p[MAXE];
    int main(){
    	//freopen("test.in", "r", stdin);
        //freopen("test.out", "w", stdout);
        int n, path, t;
        scanf("%d %d %d", &n, &path, &t);
        for (int i = 0; i < path; i ++){
            scanf("%d %d %d", &p[i].u, &p[i].v, &p[i].w);
        }
        int l = 0, r = 1000005;
        while(l < r){
            int mid = MID(l, r);
            dinic.init(n+2);
            for (int i = 0; i < path; i ++){
                if (p[i].w <= mid)
                    dinic.insert_flow(p[i].u, p[i].v, 1);
            }
            dinic.insert_flow(n+1, 1, t);
            dinic.insert_flow(n, n+2, t);
            int res = dinic.solve(n+1, n+2);
            if (res == t){
                r = mid;
            }
            else{
                l = mid + 1;
            }
        }
        printf("%d
    ", r);
    	return 0;
    }
    
     
  • 相关阅读:
    CSS深入之第四天
    CSS之第三天总结
    第二天对CSS的学习
    开始走进CSS世界
    Hbuilder实用技巧
    项目总结
    CSS3的chapter6
    CSS3的chapter5
    CSS3的chapter4
    CSS3的chapter3
  • 原文地址:https://www.cnblogs.com/AbandonZHANG/p/4114258.html
Copyright © 2011-2022 走看看