hrbust 1798 秘密产奶机器【二分+最大流】

秘密产奶机器
Time Limit: 6000 MSMemory Limit: 32768 K
Total Submit: 11(7 users)Total Accepted: 7(6 users)Rating: Special Judge: No
Description

John正在建造一种新型的产奶机器并且希望可以保守住这个秘密尽可能长的时间。他已经把机器藏在了他的农场里的一个秘密场所并且他需要在接近这台机器的时候不被发现。在机器建造过程中,他必须要走T(1<=T<=200)次通向他的机器的路径。而且他有一个秘密的地下通道,但是这个通道仅仅是在返回时使用的。

农场有N2<=N<=200)个地标(从1N编号),并且有P1<=P<=40000)个双向道路(从1P编号)连接这些地标,每条道路都有一个权值w表示该路的长度(1<=w<=1000000)。

需要注意的是两个地标之间可能会有多条道路相连。

为了防止被发现,每条道路John只能够通过一次,并且他希望尽可能的短一点的路。请帮助John算出在走向目标点这T次走的路径中,他需要经过的所有道路里最长的道路最短可以是多少。

题目保证John可以找到T条通向终点的路径。

Input

多组测试数据。

对于每组测试数据:

第一行输入三个整数N,PT

接下来的P行,每行输入三个整数a,b,w分别表示有一条连接 a 和 b 地标且长度为w的道路。

Output
对于每组测试数据输出一个整数表示John所需要经过的道路中最长的道路最短可以是多少。
Sample Input

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

Sample Output
5
Hint
John can travel trails 1 - 2 - 3 - 7 and 1 - 6 - 7. None of the trails travelled exceeds 5 units in length. It is impossible for Farmer John to travel from 1 to 7 twice without using at least one trail of length 5. 

Huge input data,scanf is recommended.
Recommend
周洲 @Hrbust

同Poj 2455


思路:

1、首先,我们想要找这样一个值最暴力最简单的方式就是枚举,然而因为枚举一定超时,而且考虑到找到的种类数会随着枚举出来的值增加而增加,满足单调递增性,那么我们二分查找ans,设定当前枚举到的值是mid;


2、根据当前值mid建图:

①设定源点S,连入节点1,设定权值为INF,表示期望获得无数条可行路径。

②设定汇点T,将n连入汇点,设定权值为INF,表示期望获得无数条可行路径。

③将m条无向边进行判断,其两点间距离如果小于等于mid,那么建立当前边(注意是无向),设定权值为1,表示这条边只能走一次(因为找到的每一种路径都不能有重复边)。


3、然后不断在二分过程中跑最大流,跑得一次最大流,如果其maxflow>=t(注意不是正好要t种路径,而是找到t种就可以,所以是大于等于),记录ans=mid,一直二分下去,直到不能二分为止。


4、直接枚举上界为1000000会TLE,需要枚举上界为最大边权值才能过。


Ac代码:


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
struct node
{
    int from;
    int to;
    int w;
    int next;
}e[20000400];
int n,m,t,cont,ss,tt;
int divv[20000];
int cur[20000];
int head[20000];
int bian[400060][3];
void add(int from,int to,int w)
{
    e[cont].to=to;
    e[cont].w=w;
    e[cont].next=head[from];
    head[from]=cont++;
}
void getmap(int mid)
{
    ss=n+1;
    tt=ss+1;
    cont=0;
    memset(head,-1,sizeof(head));
    add(ss,1,0x3f3f3f3f);
    add(1,ss,0);
    add(n,tt,0x3f3f3f3f);
    add(tt,n,0);
    for(int i=0;i<m;i++)
    {
        if(bian[i][2]<=mid)
        {
            add(bian[i][0],bian[i][1],1);
            add(bian[i][1],bian[i][0],0);
            add(bian[i][1],bian[i][0],1);
            add(bian[i][0],bian[i][1],0);
        }
    }
}
int makedivv()
{
    memset(divv,0,sizeof(divv));
    queue<int >s;
    s.push(ss);
    divv[ss]=1;
    while(!s.empty())
    {
        int u=s.front();
        if(u==tt)return 1;
        s.pop();
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            int w=e[i].w;
            if(w&&divv[v]==0)
            {
                divv[v]=divv[u]+1;
                s.push(v);
            }
        }
    }
    return 0;
}
int Dfs(int u,int maxflow,int tt)
{
    if(u==tt)return maxflow;
    int ret=0;
    for(int &i=cur[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        int w=e[i].w;
        if(w&&divv[v]==divv[u]+1)
        {
            int f=Dfs(v,min(maxflow-ret,w),tt);
            e[i].w-=f;
            e[i^1].w+=f;
            ret+=f;
            if(ret==maxflow)return ret;
        }
    }
    return ret;
}
int Slove(int mid)
{
    getmap(mid);
    int ans=0;
    while(makedivv()==1)
    {
        memcpy(cur,head,sizeof(head));
        ans+=Dfs(ss,0x3f3f3f3f,tt);
    }
    //printf("%d %d\n",mid,ans);
    if(ans>=t)
    return 1;
    else return 0;
}
int main()
{
    while(~scanf("%d%d%d",&n,&m,&t))
    {
        int maxn=0;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&bian[i][0],&bian[i][1],&bian[i][2]);
            maxn=max(maxn,bian[i][2]);
        }
        int mid;
        int ans;
        int l=0;
        int r=maxn+2;
        while(r>=l)
        {
            mid=(l+r)/2;
            if(Slove(mid)==1)
            {
                r=mid-1;
                ans=mid;
            }
            else l=mid+1;
        }
        printf("%d\n",ans);
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值