poj 2455

     题目要求找出网络中从给定起点到终点的不少于t条的路径,使得路径中相邻结点间的最长路最短。

     一般的,解决多结点间的多重最值问题,尤其是最短路中的最长路等问题,都要使用网络流做模型,利用最大流来判断方案的存在性,而其中的最值问题则可能会使用最短路算法或者是贪心,poj2391就用到了最短路,而本题则是用到了“贪心”,即必须先对所有的路按其长度递增排序。然后二分,取标号在mid之前的所有路建图,每条边的容量均为1,求最大流,若最大流的大于等于t,则标号为mid的边的权值即为所求。

      一开始时看到有重边就用贪心,任意两个结点只留下最小权值边,结果一直wa,因为存在反例:1->2->4,1->3->4.若前者是重边且有两个权值5,6,后者是单边,有权值7,t=2时,正确答案为6,若按照我之前的做法,则6要排除,故答案为7,错了。所以,网络流中的删边、增边必须要小心。

 

      以下是代码:

 

  1. #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int inf=1<<29;
    const int M=90020;
    const int N=400;
  2. struct node
    {
     int u,v,w;
     int next;
     bool operator <(const node a)const
     {
      return w<a.w;
     }
    }edge[M];
    int head[N],num;
    int level[N],queue[2*N];
    int cap[N][N],flow[N][N];
    int n,p,t;
  3. void init()
    {
     memset(flow,0,sizeof(flow));
     memset(cap,0,sizeof(cap));
    }
  4. int dinic_dfs(int star,int end,int ver)
    {
     int stack[10*N],top=0;
     int maxflow=0,cur,minf,ptr;
     int i;
     stack[top++]=star;
     cur=star;
     while(top)
     {
      cur=stack[top-1];
      if(cur==end)
      {
       minf=inf;
       for(i=1;i<top;i++)
       {
        if(minf>cap[stack[i-1]][stack[i]]-flow[stack[i-1]][stack[i]])
        {
         minf=cap[stack[i-1]][stack[i]]-flow[stack[i-1]][stack[i]];
         ptr=i;
        }
       }
       maxflow+=minf;
       for(i=1;i<top;i++)
       {
        flow[stack[i-1]][stack[i]]+=minf;
        flow[stack[i]][stack[i-1]]-=minf;
       }
       top=ptr;
      }
      else
      {
       for(i=1;i<=n;i++)
       {
        if(level[i]==level[cur]+1 && cap[cur][i]>flow[cur][i])
        {
         stack[top++]=i;
         break;
        }
       }
       if(i==n+1)
       {
        level[cur]=-1;
        top--;
       }
      }
     }
     return maxflow;
    }
  5. bool dinic_bfs(int star,int end,int ver)
    {
     int queue[10*N],rear=0;
     int i,j;
     for(i=1;i<=ver;i++)
     {
      level[i]=-1;
     }
     queue[rear++]=star;
     level[star]=0;
     for(i=0;i<rear;i++)
     {
      for(j=1;j<=n;j++)
      {
       if(level[j]==-1 && cap[queue[i]][j]>flow[queue[i]][j])
       {
        level[j]=level[queue[i]]+1;
        queue[rear++]=j;
       }
      }
     }
     return level[end]>=0;
    }
  6. int dinic(int star,int end,int ver)
    {
     int flow=0,t;
     while(dinic_bfs(star,end,ver))
     {
      t=dinic_dfs(star,end,ver);
      if(t) flow+=t;
      else break;
     }
     return flow;
    }
  7. bool check(int mid)
    {
     init();
     int s1,t1;
     int i;
     for(i=0;i<=mid;i++)
     {
      cap[edge[i].u][edge[i].v]++;
      cap[edge[i].v][edge[i].u]++;
     }
     s1=1;t1=n;
     return dinic(s1,t1,n)>=t;
    }
  8. int main()
    {
     scanf("%d%d%d",&n,&p,&t);
     int i;
     for(i=0;i<p;i++)
     {
      int a,b;
      int c;
      scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
     }
     sort(edge,edge+p);
     int low=0,high=p-1;
     int ans=0;
     while(low<=high)
     {
      int mid=(low+high)/2;
      if(check(mid))
      {
       ans=edge[mid].w;
       high=mid-1;
      }
      else low=mid+1;
     }
     printf("%d/n",ans);
     return 0;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值