[zoj] 3496 Assignment || 有源汇上下界最大流

原题

贴个博客

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 510
#define M 10010
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
struct hhh
{
    int to,next;
    ll w;
}edge[2*M];
int Q,n,m,s,t,p,ss,tt,sum,q[N],x,y,cnt=1,head[N],dis[N],cur[N],tot,u[M],v[M];
ll extra[N],w[M],mx;

ll read()
{
    ll ans=0,fu=1;
    char j=getchar();
    for (;j<'0' || j>'9';j=getchar()) if (j=='-') fu=-1;
    for (;j>='0' && j<='9';j=getchar()) ans*=10,ans+=j-'0';
    return ans*fu;
}

void add(int u,int v,ll w)
{
    edge[cnt].to=v;edge[cnt].next=head[u];edge[cnt].w=w;head[u]=cnt++;
    edge[cnt].to=u;edge[cnt].next=head[v];edge[cnt].w=0;head[v]=cnt++;
}

void ADD(int u,int v,ll b,ll c)
{
    extra[u]-=b;extra[v]+=b;
    add(u,v,c-b);
}

bool bfs(int S,int T)
{
    int r;
    for (int i=0;i<=n+m+3;i++)
    cur[i]=head[i],dis[i]=-1;
    dis[S]=1;
    q[r=1]=S;
    for (int l=1;l<=r;l++)
    {
    int u=q[l];
    for (int i=head[u],v;i;i=edge[i].next)
        if (edge[i].w>0 && dis[v=edge[i].to]==-1)
        {
        dis[v]=dis[u]+1;
        q[++r]=v;
        if (v==T) return 1;
        }
    }
    return 0;
}

ll dfs(int u,ll flow,int T)
{
    if (u==T) return flow;
    ll ret=0,delta;
    for (int &i=cur[u],v;i;i=edge[i].next)
    if (edge[i].w>0 && dis[v=edge[i].to]==dis[u]+1)
    {
        delta=dfs(v,min(edge[i].w,flow-ret),T);
        if (delta)
        {
        edge[i].w-=delta;
        edge[i^1].w+=delta;
        ret+=delta;
        if (ret==flow) break;
        }
    }
    return ret;
}

ll dinic(int S,int T)
{
    ll ans=0;
    while (bfs(S,T))
    ans+=dfs(S,inf,T);
    return ans;
}

ll buildGraph(ll x,ll y)
{
    cnt=2;
    sum=0;
    memset(head,0,sizeof(head));
    memset(extra,0,sizeof(extra));
    for (int i=1;i<=m;i++)
    ADD(u[i],v[i],x,min(w[i],y));
    for (int i=1;i<=n;i++)
    {
    if (extra[i]>0) add(ss,i,extra[i]),sum+=extra[i];
    if (extra[i]<0) add(i,tt,-extra[i]);
    }
    add(t,s,inf);
    ll tmp=dinic(ss,tt);
    if (tmp!=sum) return -1;
    printf("!%d!\n",tmp);
    ///*
    for (int i=head[ss];i;i=edge[i].next)
    edge[i].w=edge[i^1].w=0;
    for (int i=head[tt];i;i=edge[i].next)
    edge[i].w=edge[i^1].w=0;
    edge[cnt-1].w=edge[cnt-2].w=0;
    //*/
    return tmp+dinic(s,t);
}

int main()
{
    Q=read();
    int l,r;
    while (Q--)
    {
    scanf("%d%d%d%d%d",&n,&m,&s,&t,&p);
    s++;t++;n++;
    ss=0;tt=n+1;
    if (m==0)
    {
        printf("0 0\n");
        continue;
    }
    for (int i=1;i<=m;i++)
        u[i]=read()+1,v[i]=read()+1,w[i]=read(),mx=max(mx,w[i]);
    ll mxflow=buildGraph(0,inf);
    l=0;r=mx;
    while (l!=r)// max min
    {
        int mid=(l+r)>>1;
        if (buildGraph(0,mid)==mxflow) r=mid;
        else l=mid+1;
    }
    printf("mxflow: %lld\n",mxflow);
    printf("%lld ",(ll)l*p);
    l=0;r=mx;
    while (l!=r)//min max
    {
        int mid=(l+r+1)>>1;
        printf("::%d %d %d\n",l,mid,r);
        int ans=buildGraph(mid,inf);
        printf("%d\n",ans);
        if (ans==mxflow) l=mid;
        else r=mid-1;
    }
    printf("%lld\n",(ll)r*p);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/mrha/p/8227942.html

时间: 2024-08-01 18:21:49

[zoj] 3496 Assignment || 有源汇上下界最大流的相关文章

[zoj] 3229 Shoot the Bullet || 有源汇上下界最大流

zoj 文文要给幻想乡的女孩子们拍照,一共n天,m个女孩子,每天文文至多拍D[i]张照片,每个女孩子总共要被文文至少拍G[i]次.在第i天,文文可以拍c[i]个女孩子,c[i]个女孩子中每个女孩子在当天被拍的次数是[l,r],求最多可以拍多少张照片,以及每天每个可以拍的女孩子被拍了多少张照片. 有源汇上下界最大流. 先跑有源汇上下界可行流,判断是否可行,若可行则此时跑原图中s到t的最大流即为答案. //代码与题解不符-- #include<cstdio> #include<algorit

zoj 3229 Shoot the Bullet(有源汇上下界最大流)

Shoot the Bullethttp://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3442 Time Limit: 2 Seconds      Memory Limit: 32768 KB      Special Judge Gensokyo is a world which exists quietly beside ours, separated by a mystical border. It is a utopia

POJ2396&amp;ZOJ1994--Budget【有源汇上下界可行流】

链接:http://poj.org/problem?id=2396 题意:给一个n*m的矩阵,给出每行的总和以及每列的总和,再给出某些位置的最小或最大限制,问是否存在可能的矩阵,如果存在输出一种矩阵信息. 思路:这是一个有源汇的上下界可行流,对于这种题,从汇点连一条弧到源点,容量为INF,这不会影响流量平衡条件,并且此时原图转换为了无源汇的上下界可行流,剩下的做法和无源汇一样. 建图:原图源点src连向每个行顶点,容量为每行的和,每个列顶点连向汇点,容量为每个列顶点的和,行顶点和列顶点间也各有一

有源汇上下界可行流(POJ2396)

题意:给出一个n*m的矩阵的每行和及每列和,还有一些格子的限制,求一组合法方案. 源点向行,汇点向列,连一条上下界均为和的边. 对于某格的限制,从它所在行向所在列连其上下界的边. 求有源汇上下界可行流即可. 具体做法可以从汇点向源点连容量为正无穷的边,转成无源汇上下界可行流. 然后可以新建超级源汇,对于一条下界为l,上界为r的边(x,y),从超级源点向y,x向超级汇点连容量为l的边,x向y连容量为r-l的边. 如果那些容量为l的边没满流,则无解. #include <cstdio> #incl

算法复习——有源汇上下界可行流(bzoj2396)

题目: Description We are supposed to make a budget proposal for this multi-site competition. The budget proposal is a matrix where the rows represent different kinds of expenses and the columns represent different sites. We had a meeting about this, so

zoj3229 有源汇上下界最大流

题意:有一个人每天给妹子拍照,每个妹子有最少拍照数,每天有最大拍照数,每天只能给某些特定的妹子拍照,求最大拍照数 题解:很容易看出来的有源汇上下界最大流,对于有源汇 的上下界最大流,我们按照无源汇的操作连边,然后从汇点连一条边到源点,容量无穷大,下界为0,从超级源ss到超级汇tt跑一遍最大流,求得的流量就是可行流 的流量,此时求出来的只是可行流并不是最大流,我们还需要从原来的s到t跑一边最大流,最后的最大流就是可行流 的流量+新增广的s-t流量 ps:这题样例一直过不了,但是我发现很多博客代码的

hdu3157有源汇上下界最小流

题意:有源汇上下界最小流裸题,主要就是输入要用字符串的问题 #include<bits/stdc++.h> #define fi first #define se second #define mp make_pair #define pb push_back #define pii pair<int,int> #define C 0.5772156649 #define pi acos(-1.0) #define ll long long #define mod 10000000

sgu176 有源汇上下界最小流

题意:有一堆点和边,1起点,n终点,某些边有可能必须满流,要求满足条件的最小流 解法:按原图建边,满流的即上下界都是容量,但是这样按有源汇上下界可行流求出来的可能不是最小流,那么我们需要开始建边的时候不要建从t到s的边,先跑一边从ss到tt的最大流,然后把该边加上再跑一次从ss到tt的最大流,那么从t到s的反向边流过的流量就是原图的最小流,为什么是这样呢,这是因为当我们第一遍跑最大流的时候,此时没有t到s的这条边,那么图中的流量会尽量按其他的边流,当我们第二次跑最大流的时候,流出来的都是第一次中

[hdu] 3157 Crazy Circuits || 有源汇上下界最小流

原题 有两个正负极n个节点和m个元件,每个元件告诉端点是接在哪个节点上的,并且每个元件有工作的最小电流限制,问使所有元件工作的满足条件的最小电流是多少. 有源汇上下界最小流. 考虑dinic的推流思想,所以在跑完可行流后,减去t到s的最大流就是最小流. 实现方法: 建图时先不加入t到s的inf边,跑最大流,再加入inf边跑最大流.若此刻是可行流,那么加入的t到s的inf边的反向边的权值就是最小流. ll ans=0; ans+=dinic(); add(t,s,inf); ans+=dinic(