POJ 1459

题目:http://poj.org/problem?id=1459
这是典型的网络最大流的题目了。以前用的是EK,BFS的次数太多了。太慢了。
这次找了别人的dicnic模板了。直接贴上来了。

#include <stdio.h>  
#include <string.h>  
#define VM 2000  
#define EM 205500  
#define inf 0x3f3f3f3f  
struct Edge  
{  
    int frm,to,cap,next;  
}edge[EM];  

int head[VM],dep[VM],ep;     //dep为点的层次  
void addedge (int cu,int cv,int cw)  //第一条边下标必须为偶数  
{  
    edge[ep].frm = cu;  
    edge[ep].to = cv;  
    edge[ep].cap = cw;  
    edge[ep].next = head[cu];  
    head[cu] = ep;  
    ep ++;  
    edge[ep].frm = cv;  
    edge[ep].to = cu;  
    edge[ep].cap = 0;  
    edge[ep].next = head[cv];  
    head[cv] = ep;  
    ep ++;  
}  

int BFS (int src,int des)     //求出层次图  
{  
    int que[VM],i,front = 0,rear = 0;  
    memset (dep,-1,sizeof(dep));  
    que[rear++] = src;  
    dep[src] = 0;  
    while (front != rear)  
    {  
        int u = que[front++];  
        front = front%VM;  
        for (i = head[u];i != -1;i = edge[i].next)  
        {  
            int v = edge[i].to;  
            if (edge[i].cap > 0&&dep[v] == -1) //容量大于0&&未在dep中  
            {  
                dep[v] = dep[u] + 1;        //建立层次图  
                que[rear ++] = v;  
                rear = rear % VM;  
                if (v == des)  //找到汇点 返回  
                    return 1;  
            }  
        }  
    }  
    return 0;  
}  
int dinic (int src,int des)  
{  
    int i,res = 0,top;  
    int stack[VM];    //stack为栈,存储当前增广路  
    int cur[VM];        //存储当前点的后继 跟head是一样的  
    while (BFS(src,des))   //if BFS找到增广路  
    {  
        memcpy (cur,head,sizeof (head));  
        int u = src;       //u为当前结点  
        top = 0;  
        while (1)  
        {  
            if (u == des)     //增广路已全部进栈  
            {  
                int min = inf,loc ;  
                for (i = 0;i < top;i ++)       //找最小的增广跟并loc记录其在stack中位置  
                    if (min > edge[stack[i]].cap)  //以便退回该边继续DFS  
                    {  
                        min = edge[stack[i]].cap;  
                        loc = i;  
                    }  
                for (i = 0;i < top;i ++)   //偶数^1 相当加1 奇数^1相当减1 当正向边 = 0&&路径不合适时,正加负减  
                {                           //偶数是正向边,奇数是负向边,边从0开始  
                    edge[stack[i]].cap -= min;  
                    edge[stack[i]^1].cap += min;  
                }                              //将增广路中的所有边修改  
                res += min;  
                top = loc;  
                u = edge[stack[top]].frm;         //当前结点修改为最小边的起点  
            }  
            for (i = cur[u];i != -1;cur[u] = i = edge[i].next)   //找到当前结点对应的下一条边  
                if (edge[i].cap != 0&&dep[u] + 1 == dep[edge[i].to])//不满足条件时,修改cur值(去掉不合适的占)eg:1-->2 1-->3 1-->4 有边 但只有  
                    break;                                  // 1-->4 这条边满足条件 就把1到2、3的边给去掉  
            if (cur[u] != -1)            //当前结点的下一条边存在  
            {  
                stack[top ++] = cur[u];   //把该边放入栈中  
                u = edge[cur[u]].to;         //再从下个点开始找  
            }  
            else  
            {  
                if (top == 0)        //当前结点无未遍历的下一条边且栈空,DFS找不到下一条增广路  
                    break;  
                dep[u] = -1;            //当前结点不在增广路中,剔除该点  
                u = edge[stack[--top]].frm; //退栈 回朔,继续查找  
            }  
        }  
    }  
    return res;  
}  
int main ()///坐标从0或1开始均可  注意别忘记下面的2个初始化  
{  
    int np,nc,m,v1,v2,w,n;  
    int src,des;  
    char str[20];  
    while (scanf ("%d%d%d%d",&n,&np,&nc,&m)!=EOF)  
    {  
        ep = 0;//边的初始化  
        src = n;  
        des = n+1;  
        memset (head,-1,sizeof(head));///这里初始化  
        while (m --)  
        {  
            scanf ("%s",str);  
            sscanf (str,"(%d,%d)%d",&v1,&v2,&w);  
            addedge (v1,v2,w);  
        }  
        while (np --)  
        {  
            scanf ("%s",str);  
            sscanf (str,"(%d)%d",&v2,&w);  
            addedge (src,v2,w);  
        }  
        while (nc--)  
        {  
            scanf ("%s",str);  
            sscanf (str,"(%d)%d",&v1,&w);  
            addedge (v1,des,w);  
        }  
        int ans = dinic (src,des);  
        printf ("%d\n",ans);  
    }  
    return 0;  
} 

猜你喜欢

转载自blog.csdn.net/qq_38987374/article/details/80117700