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

zoj

文文要给幻想乡的女孩子们拍照,一共n天,m个女孩子,每天文文至多拍D[i]张照片,每个女孩子总共要被文文至少拍G[i]次。在第i天,文文可以拍c[i]个女孩子,c[i]个女孩子中每个女孩子在当天被拍的次数是[l,r],求最多可以拍多少张照片,以及每天每个可以拍的女孩子被拍了多少张照片。



有源汇上下界最大流。

先跑有源汇上下界可行流,判断是否可行,若可行则此时跑原图中s到t的最大流即为答案。
//代码与题解不符……

#include<cstdio>
#include<algorithm>
#define N 2010
#define M 100010
#define inf 0x3f3f3f3f
using namespace std;
struct hhh
{
    int to,w,next,num;
}edge[M];
int cnt=1,head[N],dis[N],cur[N],tot;
int n,m,s,t,ss,tt,sum,q[N],r,ans[M],extra[N],x,y,low[M];

int read()
{
    int 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 init()
{
    s=0;t=n+m+1;
    ss=t+1;tt=t+2;
    sum=tot=0;
    cnt=2;
    for (int i=s;i<=tt;i++)
    extra[i]=head[i]=0;
}

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

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

bool bfs(int S,int T)
{
    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 && dis[v=edge[i].to]==-1)
        {
        dis[v]=dis[u]+1;
        q[++r]=v;
        if (v==T) return 1;
        }
    }
    return 0;
}

int dfs(int u,int flow,int T)
{
    if (u==T) return flow;
    int ret=0,delta;
    for (int &i=cur[u],v;i;i=edge[i].next)
    if (edge[i].w && 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;
}

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

int main()
{
    while (~scanf("%d%d",&n,&m))
    {
    init();
    for (int i=1;i<=m;i++)
    {
        x=read();
        ADD(n+i,t,x,inf,0);
    }
    for (int i=1;i<=n;i++)
    {
        x=read();y=read();
        ADD(s,i,0,y,0);
        for (int j=1,l,h;j<=x;j++)
        {
        ++tot;
        y=read();l=read();h=read();
        ADD(i,n+y+1,l,h,tot);
        low[tot]=l;
        }
    }
    for (int i=s;i<=t;i++)
    {
        if (extra[i]>0) add(ss,i,extra[i],0),sum+=extra[i];
        if (extra[i]<0) add(i,tt,-extra[i],0);
    }
    add(t,s,inf,0);
    if (dinic(ss,tt)==sum)
    {
        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;
        int flow=edge[cnt-1].w;
        edge[cnt-1].w=edge[cnt-2].w=0;
        printf("%d\n",flow+dinic(s,t));
        for (int i=1;i<=m;i++)
        for (int j=head[i+n];j;j=edge[j].next)
            if (edge[j].num!=0)
            ans[edge[j].num]=edge[j].w+low[edge[j].num];
        for (int i=1;i<=tot;i++)
        printf("%d\n",ans[i]);
    }
    else printf("-1\n");
    putchar('\n');
    }
    return 0;
}

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

时间: 2024-10-13 06:03:26

[zoj] 3229 Shoot the Bullet || 有源汇上下界最大流的相关文章

ZOJ 3229 Shoot the Bullet 无源汇上下界最大流

Shoot the Bullet 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 where humans and other beings such as fairies, youkai(phantoms)

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(