Secret Milking Machine

来源:互联网 发布:盛世尊享年金保险 知乎 编辑:程序博客网 时间:2024/06/01 09:39

题意:给出一个图,从起点到终点,t条路径中最长边的最短是多少。

思路:最大流+二分。sap的模板。注意此题要用scanf与printf,否则会TLE滴。

 

#include<iostream>#include<string.h>#include<stdio.h>#define VM 4005#define INF  0x3f3f3f3fusing namespace std;int n,m;int s,sink;int head[VM],dep[VM],gap[VM];struct node{    int frm;    int to;    int cap;    int next;}edge[999999];struct node1{    int u;    int v;    int c;}p[999999];int tot;int tmpn;void add(int u, int v, int c){    edge[tot].frm = u;    edge[tot].to = v;    edge[tot].cap = c;    edge[tot].next = head[u];    head[u] = tot++;    edge[tot].frm = v;    edge[tot].to = u;    edge[tot].cap = 0;    edge[tot].next = head[v];    head[v] = tot++;}void BFS(int src, int des){    memset(dep, -1, sizeof(dep));    memset(gap, 0, sizeof(gap));    gap[0] = 1;   //说明此时有1个dep[i] = 0    int Q[VM], front = 0, rear = 0;    dep[des] = 0;    Q[rear++] = des;    int u, v;    while (front != rear)    {        u = Q[front++];        front = front%VM;        for (int i=head[u]; i!=-1; i=edge[i].next)        {            v = edge[i].to;            if (edge[i].cap != 0 || dep[v] != -1)                continue;            Q[rear++] = v;            rear = rear % VM;            ++gap[dep[v] = dep[u] + 1];  //求出各层次的数量        }    }}int SAP(int src, int des){    int res = 0;    BFS(src, des);    int cur[VM];    int S[VM], top = 0;    memcpy(cur, head, sizeof(head));    int u = src, i;    while (dep[src] < n)   //n为结点的个数    {        if (u == des)        {            int temp = INF, inser = n;            for (i=0; i!=top; ++i)                if (temp > edge[S[i]].cap)                {                    temp = edge[S[i]].cap;                    inser = i;                }            for (i=0; i!=top; ++i)            {                edge[S[i]].cap -= temp;                edge[S[i]^1].cap += temp;            }            res += temp;            top = inser;            u = edge[S[top]].frm;        }        if (u != des && gap[dep[u] -1] == 0)//出现断层,无增广路            break;        for (i = cur[u]; i != -1; i = edge[i].next)//遍历与u相连的未遍历结点            if (edge[i].cap != 0 && dep[u] == dep[edge[i].to] + 1) //层序关系, 找到允许                break;        if (i != -1)//找到允许弧        {            cur[u] = i;            S[top++] = i;//加入路径栈            u = edge[i].to;//查找下一个结点        }        else   //无允许的路径,修改标号当前点的标号比与之相连的点中最小的多1        {            int min = n;            for (i = head[u]; i != -1; i = edge[i].next) //找到与u相连的v中dep[v]最小的点            {                if (edge[i].cap == 0)                    continue;                if (min > dep[edge[i].to])                {                    min = dep[edge[i].to];                    cur[u] = i;          //最小标号就是最新的允许弧                }            }            --gap[dep[u]];          //dep[u] 的个数变化了 所以修改gap            ++gap[dep[u] = min + 1]; //将dep[u]设为min(dep[v]) + 1, 同时修改相应的gap[]            if (u != src) //该点非源点&&以u开始的允许弧不存在,退点                u = edge[S[--top]].frm;        }    }    return res;}int isBuild(int mid,int tt){    memset(head,-1,sizeof(head));    tot=0;    add(s,1,tt);    for(int i=0;i<m;i++)    {        if(p[i].c<=mid)//小于中间流量的建边        {            add(p[i].u,p[i].v,1);            add(p[i].v,p[i].u,1);        }    }    add(tmpn,sink,tt);    if(SAP(s,sink)>=tt)    return 1;    return 0;}int main(){    int minc,maxc;    int t;    while(scanf("%d%d%d",&n,&m,&t)!=EOF)    {        minc=99999999;        maxc=0;        tmpn=n;        s=0;        sink=n+1;        n+=2;        for(int i=0;i<m;i++)        {            scanf("%d%d%d",&p[i].u,&p[i].v,&p[i].c);            if(minc>p[i].c)            minc=p[i].c;            if(maxc<p[i].c)            maxc=p[i].c;        }        int ans=0;        while(minc<=maxc)//二分        {            int mid=(maxc+minc)>>1;            if(isBuild(mid,t))            {                maxc=mid-1;                ans=mid;            }            else            minc=mid+1;        }       printf("%d\n",ans);    }    return 0;}


另一个sap模板,其实 差不多。

#include<iostream>#include<string.h>#include<stdio.h>#define VM 4005#define INF  0x3f3f3f3fusing namespace std;int n,m;int s,sink;int head[VM],dist[VM],gap[VM],cur[VM],pre[VM];struct node{    int to;    int cap;    int nxt;}edge[999999];struct node1{    int u;    int v;    int c;}p[999999];int ep;int tmpn;void add(int cu,int cv,int cw){    edge[ep].to = cv;    edge[ep].cap = cw;    edge[ep].nxt = head[cu];    head[cu] = ep;    ep ++;    edge[ep].to = cu;    edge[ep].cap = 0;    edge[ep].nxt = head[cv];    head[cv] = ep;    ep ++;}int min (int a ,int b){   return a > b ? b : a;}int sap (int src,int des,int n){    memset (dist,0,sizeof(dist));    memset (gap,0,sizeof (dist));    memcpy (cur,head,sizeof(dist));    int res = 0;    int u = pre[src] = src;    int aug = INF;    gap[0] = n;    while (dist[src] < n)    {loop:        for (int &i = cur[u];i != -1;i = edge[i].nxt)        {            int v = edge[i].to;            if (edge[i].cap && dist[u] == dist[v] + 1)            {                aug = min (aug,edge[i].cap);                pre[v] = u;                u = v;                if (v == des)                {                    res += aug;                    for (u = pre[u];v != src;v = u,u = pre[u])                    {                        edge[cur[u]].cap -= aug;                        edge[cur[u]^1].cap += aug;                    }                    aug = INF; //                }                goto loop;            }        }        int mindist = n;  //        for (int i = head[u];i != -1;i = edge[i].nxt)        {            int v = edge[i].to;            if (edge[i].cap && mindist > dist[v])            {                cur[u] = i;                mindist = dist[v];            }        }        if ((--gap[dist[u]]) == 0)            break;        dist[u] = mindist + 1;        gap[dist[u]] ++;        u = pre[u];    }    return res;}int isBuild(int mid,int tt){    memset(head,-1,sizeof(head));    ep=0;    add(s,1,tt);    for(int i=0;i<m;i++)    {        if(p[i].c<=mid)        {            add(p[i].u,p[i].v,1);            add(p[i].v,p[i].u,1);        }    }    add(tmpn,sink,tt);    if(sap(s,sink,n)>=tt)    return 1;    return 0;}int main(){    int minc,maxc;    int t;    while(scanf("%d%d%d",&n,&m,&t)!=EOF)    {        minc=99999999;        maxc=0;        tmpn=n;        s=0;        sink=n+1;        n+=2;        for(int i=0;i<m;i++)        {            scanf("%d%d%d",&p[i].u,&p[i].v,&p[i].c);            if(minc>p[i].c)            minc=p[i].c;            if(maxc<p[i].c)            maxc=p[i].c;        }        int ans=0;        while(minc<=maxc)        {            int mid=(maxc+minc)>>1;            if(isBuild(mid,t))            {                maxc=mid-1;                ans=mid;            }            else            minc=mid+1;        }        printf("%d\n",ans);    }    return 0;}