poj2391 二分最大流+拆点

来源:互联网 发布:17年华研网络词作大赛 编辑:程序博客网 时间:2024/06/05 09:18

这道题范围开的非常的憋屈人 

首先建立一个超级源点 编号是0 一个超级汇点 编号是2*f+1

将每个避雨点分成两个点 第一组编号为1~f 对应的第二组为f+1~2*f

每次建图 从源点向第一组每个避雨点连边 边的值为现在停留在这个点的牛的数量

从第二组每个点向汇点进行连边 边的值为这个点可容纳的牛的数量

然后对时间进行二分 如果从避雨点i走到避雨点j的时间小于等于mid

那么就从i到j+f建一条边 边的值为INF 这样 如果某个点牛的数量超过了容纳量 这个点的牛就可以流到其他的点了

然后从0到2*f+1跑最大流 如果最大流>=牛的总数量 那么mid有减小的余地 最后输出ans即可



#include<algorithm>#include<iostream>#include<cstdlib>#include<cstring>#include<cstdio>#include<string>#include<stack>#include<queue>#include<cmath>#include<stack>#include<list>#include<set>typedef long long ll;using namespace std;const int MAXN=500;//jiedian de zui da zhiconst int MAXM=505000;//bian de zui da zhiconst int INF=0xFFFFFFF;const ll MAX=0x7FFFFFFFFFFFFFF;int bian[1505][2];ll map[205][205];struct Node{    int from,to,next;    int cap;}edge[MAXM];int tol;int head[MAXN];int dep[MAXN];int gap[MAXN];void init()  //remember write it in main function{    tol=0;    memset(head,-1,sizeof(head));}void addedge(int u,int v,int w){    edge[tol].from=u;    edge[tol].to=v;    edge[tol].cap=w;    edge[tol].next=head[u];    head[u]=tol++;    edge[tol].from=v;    edge[tol].to=u;    edge[tol].cap=0;//wuxiangtu  this place change to w;    edge[tol].next=head[v];    head[v]=tol++;}void BFS(int start,int end){    memset(dep,-1,sizeof(dep));    memset(gap,0,sizeof(gap));    gap[0]=1;    int que[MAXN];    int front,rear;    front=rear=0;    dep[end]=0;    que[rear++]=end;    while(front!=rear)    {        int u=que[front++];        if(front==MAXN)front=0;        for(int i=head[u];i!=-1;i=edge[i].next)        {            int v=edge[i].to;            if(dep[v]!=-1)continue;            que[rear++]=v;            if(rear==MAXN)rear=0;            dep[v]=dep[u]+1;            ++gap[dep[v]];        }    }}int SAP(int start,int end,int n) //n shi jiedian de zui da ge shu ,including source and sink{    int res=0;    BFS(start,end);    int cur[MAXN];    int S[MAXN];    int top=0;    memcpy(cur,head,sizeof(head));    int u=start;    int i;    while(dep[start]<n)    {        if(u==end)        {            int temp=INF;            int inser;            for(i=0;i<top;i++)                if(temp>edge[S[i]].cap)                {                    temp=edge[S[i]].cap;                    inser=i;                }            for(i=0;i<top;i++)            {                edge[S[i]].cap-=temp;                edge[S[i]^1].cap+=temp;            }            res+=temp;            top=inser;            u=edge[S[top]].from;        }        if(u!=end&&gap[dep[u]-1]==0)//≥ˆœ÷∂œ≤„£¨Œfi‘ˆπ„¬∑            break;        for(i=cur[u];i!=-1;i=edge[i].next)            if(edge[i].cap!=0&&dep[u]==dep[edge[i].to]+1)                break;        if(i!=-1)        {            cur[u]=i;            S[top++]=i;            u=edge[i].to;        }        else        {            int min=n;            for(i=head[u];i!=-1;i=edge[i].next)            {                if(edge[i].cap==0)continue;                if(min>dep[edge[i].to])                {                    min=dep[edge[i].to];                    cur[u]=i;                }            }            --gap[dep[u]];            dep[u]=min+1;            ++gap[dep[u]];            if(u!=start)u=edge[S[--top]].from;        }    }    return res;}void floyd(int n){            for(int i=1; i<=n; i++)        for(int j=1; j<=n; j++)            if (MAX != map[j][i])                for(int k=1; k<=n; k++)                    if (map[j][i] + map[i][k] < map[j][k])                        map[j][k] = map[j][i] + map[i][k];    }void getmap(int f,ll mid){    init();    int i,j;    for(i=1;i<=f;i++)    {        addedge(0,i,bian[i][0]);        addedge(i+f, 2*f+1, bian[i][1]);    }    for(i=1;i<=f;i++)    {        for(j=1;j<=f;j++)        {            if(map[i][j]<=mid)            {                addedge(i, f+j, INF);            }        }    }}int main(){    int i,j,f,p;    while(scanf("%d%d",&f,&p)==2)    {                for(i=1;i<=f;i++)        {            for(j=1;j<=f;j++)            {                    map[i][j]=MAX;            }            map[i][i]=0;                    }        int sum=0;                for(i=1;i<=f;i++)        {            scanf("%d%d",&bian[i][0],&bian[i][1]);            sum+=bian[i][0];                    }        //The first integer is the number of cows in that field. The second integer is the number of cows the shelter in that field can hold        ll x,y,z;        for(i=1;i<=p;i++)        {            scanf("%lld%lld%lld",&x,&y,&z);                map[x][y]=map[y][x]=min(map[x][y],z);        }        floyd(f);        ll l=0,r=MAX;        ll mid;        ll ans=-1;        while(l<r)        {            mid=(l+r)/2;            getmap(f,mid);            int tt=SAP(0, 2*f+1, 2*f+2);            if(tt>=sum)            {                r=mid;                ans=mid;                            }            else{                l=mid+1;            }        }        printf("%lld\n",ans);    }    return 0;}