POJ 2455 二分+网络流

题意:

给定n个点m条边的无向图 K值

下面给定m条边及其边权

问:

起点为1,终点为n

找到至少K条边不相交的路径,输出这个方案中所有边的最大边权

 

思路:

二分答案+网络流,使得汇点>=K即为可行解

 

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
typedef int ll;
const ll inf=10000000;
const ll maxn=2000;
ll head[maxn],tol,dep[maxn];
struct node 
{
      ll from,to,next,cap;
      node(){};
      node(ll from,ll to, ll next,ll cap):from(from),to(to),next(next),cap(cap){}
}edge[1000000],ss[1000000];
void add(ll u,ll v,ll cap)
{
      edge[tol]=node(u,v,head[u],cap);
      head[u]=tol++;
      edge[tol]=node(v,u,head[v],0);
      head[v]=tol++;
}
bool bfs(ll s,ll t)
{
       ll que[maxn],front=0,rear=0;
       memset(dep,-1,sizeof(dep));
       dep[s]=0;que[rear++]=s;
       while(front!=rear)
       {
              ll u=que[front++];front%=maxn;
              for(ll i=head[u];i!=-1;i=edge[i].next)
              {
                     ll v=edge[i].to;
                     if(edge[i].cap>0&&dep[v]==-1)
                     {
                            dep[v]=dep[u]+1;
                            que[rear++]=v;
                            rear%=maxn;
                            if(v==t)return 1;
                     }
              }
       }
       return 0;
}

ll dinic(ll s,ll t)
{
      ll res=0;
      while(bfs(s,t))
      {
	     ll Stack[maxn],top,cur[maxn];
	     memcpy(cur,head,sizeof(head));
	     top=0;
	     ll u=s;
	     while(1)
	     {
		    if(t==u)
		    {
			   ll min=inf;
			   ll loc;
			   for(ll i=0;i<top;i++)
		          if(min>edge[Stack[i]].cap)
			   {
				  min=edge[Stack[i]].cap;
				  loc=i;
			   }
			   for(ll i=0;i<top;i++)
			   {
				  edge[Stack[i]].cap-=min;
				  edge[Stack[i]^1].cap+=min;
			   }
			   res+=min;
			   top=loc;
                        u=edge[Stack[top]].from;
		    }
		    for(ll i=cur[u];i!=-1;cur[u]=i=edge[i].next)
			   if(dep[edge[i].to]==dep[u]+1&&edge[i].cap>0)break;
		    if(cur[u]!=-1)
		    {
			   Stack[top++]=cur[u];
			   u=edge[cur[u]].to;
		    }
		    else 
		    {
			   if(top==0)break;
			   dep[u]=-1;
			   u=edge[Stack[--top]].from;
		    }
	     }
      }
      return res;
}

int main()
{
     int n,m,t,i,j,k;
     while(cin>>n>>m>>t)
     {
		int left = inf, right = 0 ;
	    for(i=1;i<=m;i++)
	    {
		   scanf("%d%d%d",&ss[i].from,&ss[i].to,&ss[i].cap);
		   right = max(right, ss[i].cap);
		   left  = min(left,  ss[i].cap);
	    }
	    int ans = inf;
	    while(left<=right)
	    {
		   int mid=(left+right)>>1;

		   memset(head,-1,sizeof(head));tol=0;
		   for(i=1;i<=m;i++)  if(ss[i].cap<=mid)
				 add(ss[i].from,ss[i].to,1), add(ss[i].to, ss[i].from, 1);

		   if(dinic(1,n)>=t)right=mid-1,ans = min(ans, mid);
		   else left=mid+1;
	    }
	    cout<<ans<<endl;
     }
     return 0;
}
/*
7 9 2
1 2 2
2 3 5
3 7 5
1 4 1
4 3 1
4 5 7
5 7 1
1 6 3
6 7 3

*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值