poj 2455 Secret Milking Machine…

题意:有N个地点,FJ 想从1走到N 每条边只能走一遍 走T次 求在满足条件下,最大的边最小。
思路:这题跟 poj 3228 Gold Transportation(二分+最大流) 这题差不多,就是用二分求出满足条件下的最小边权 EK超时,此题用sap做的

//3212K      797MS
#include <stdio.h>
#include <string.h>
#define VM 210
#define EM 160010          //建边重复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
{
      int to,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];
      }
      return res;
}
int main ()
{
      int u,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);
      }
      return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值