poj 2455 Secret Milking Machine…

来源:互联网 发布:ar9565 linux 编辑:程序博客网 时间:2024/05/20 05:54
题意:有N个地点,FJ 想从1走到N 每条边只能走一遍 走T次 求在满足条件下,最大的边最小。
思路:这题跟 poj 3228 Gold Transportation(二分+最大流)这题差不多,就是用二分求出满足条件下的最小边权 EK超时,此题用sap做的

//3212K   797MS
#include <stdio.h>
#include <string.h>
#define VM 210
#define EM160010     //建边重复1遍,所以是4*40000

int head[VM],oldhead[VM],dep[VM],gap[VM],cur[VM],pre[VM];
int e1,e,n,p,t,src,des;
struct E
{
    intto,cap,nxt;
}edge[EM],oldedge[EM];

void addedge1 (int cu,int cv,int cw)
{
   oldedge[e1].to = cv;
   oldedge[e1].cap = cw;
   oldedge[e1].nxt = oldhead[cu];
    oldhead[cu]= e1 ++;
}
void addedge (int cu,int cv,int cw)
{
    edge[e].to =cv;
    edge[e].cap= cw;
    edge[e].nxt= head[cu];
    head[cu] = e++;
}

void Build (int num)  //构建一新的图
{
    memset(head,-1,sizeof(head));
    e = 0;
    for (int u =1;u <= n;u ++)
       for (int i = oldhead[u];i != -1;i = oldedge[i].nxt)
       {
           int v = oldedge[i].to;
           if (oldedge[i].cap <= num)
           {
               addedge(u,v,1);   //边权为1就可以了
               addedge (v,u,1);
           }
       }
}

int Sap ()   //sap算法,不解释
{
    memset(dep,0,sizeof(dep));
    memset(gap,0,sizeof(gap));
    memcpy(cur,head,sizeof(head));
    int u =pre[src] = src;
    int res =0;
    gap[0] =n;
    while(dep[src] < n)
    {
    loop:
       for (int &i = cur[u];i != -1;i = edge[i].nxt)
       {
           int v = edge[i].to;
           if (edge[i].cap && dep[u] == dep[v]+ 1)
           {
               pre[v] = u;
               u = v;
               if (v == des)
               {
                   res ++;   //记录走了多少次
                   for (u = pre[u];v != src;v = u,u = pre[u])
                   {
                       edge[cur[u]].cap -= 1;
                       edge[cur[u]^1].cap += 1;
                   }
               }
               goto loop;
           }

       }
       int mindep = n;
       for (int i = head[u];i != -1;i = edge[i].nxt)
       {
           int v = edge[i].to;
           if (edge[i].cap && mindep> dep[v])
           {
               cur[u] = i;
               mindep = dep[v];
           }
       }
       if ((--gap[dep[u]]) == 0)
           break;
       dep[u] = mindep + 1;
       gap[dep[u]] ++;
       u = pre[u];
    }
    returnres;
}
int main ()
{
    intu,v,w;
    while(~scanf("%d%d%d",&n,&p,&t))
    {
       memset (oldhead,-1,sizeof(oldhead));
       e1 = 0;
       src = 1,des = n;
       while (p --)
       {
           scanf("%d%d%d",&u,&v,&w);
           addedge1 (u,v,w);
           addedge1 (v,u,w);
       }
       int l = 0,r = 1000000;
       int ans = 0;
       while (l <= r)
       {
           int mid = (l + r)>>1;
           Build(mid);
           int sum = Sap ();
           sum /=2;      //这里要注意 因为建边是重复了,所以得除2 比如说:1到2有边 因为是无向图
           if (sum >= t) //当遍历到1结点时会建1-->2和2-->1,遍历到2时,会建2-->1和1-->2所以重复
           {
               ans = mid;
               r = mid - 1;
           }
           else
               l = mid + 1;
       }
       printf ("%d\n",ans);
    }
    return0;
}