Shoot the Bullet ZOJ - 3229 有源汇有上下界的最大流

/**
zoj提交评判不了,所以不知道代码正不正确。思路是应该没问题的。如果有不对的地方,请多指教。

题目:Shoot the Bullet ZOJ - 3229
链接:https://vjudge.net/problem/20756
题意:
高富帅给m个女神拍照,拍照n天,第i天给ci个女神拍照,给出了具体ci个女神的编号,以及在第i天给ci个女神分别给出拍照数量限制[l,r]。
第i天最多拍照Di次。拍照n天后,第i个女神总共最少拍照Gi次。求高富帅最多拍照次数。

思路:
建立源点s,t. s指向所有的天数,下界为0,上界为Di。所有的女神指向t,下界为Gi,上界INF。天数指向女神,下界为l,上界为r。
将有源汇有上下界变成无源汇有上界,求可行流。
t指向s,下界为0,上界为INF。增加超级源汇点S,T。
对于每个点i。in[i]表示入度的边的下界和,out[i]表示出度的边的下界和,为了进出该节点流量相等。
如果in[i]>out[i],那么S连一条到i的下界为0,上界为in[i]-out[i]的边。
如果in[i]<out[i],那么i连一条到T的下界为0,上界为out[i]-in[i]的边。

S到T跑最大流。如果flow== 所有in[i]-out[i]的和 (当in[i]>out[i]) 即:附加边都是满载。

那么有可行流。

然后在求一次s到t的最大流即是最终结果。不需要删除t到s的那条上界INF的边,也不用删除S,T.因为跑s到t的最大流的时候,t->s的流量会增广s->t回流,这里的回流值便是所有的下界和。
所以s到t的最大流就是最终的结果,已经包括了所有下界的值。
至于S,T不影响s到t的最大流,已经满载。根据dinic,只走残留网络,所以无法到达T。到达S的路径无法到达t.所以不受影响。

具体某一天某女神的拍照数量则要加上相应的下界值。

*/
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int INF = 0x3f3f3f3f;
typedef long long LL;
const int N = 1440;///n+m=1365
int in[N];
int out[N];
struct Edge{
    int from, to, cap, flow;
    Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};
struct Dinic{
    int n, m, s, t;
    vector<Edge> edges;
    vector<int> G[N];
    bool vis[N];
    int d[N];
    int cur[N];

    void init(int n)
    {
        this->n = n;
        for(int i = 0; i <= n; i++) G[i].clear();
        edges.clear();
    }

    void AddEdge(int from,int to,int cap)
    {
        edges.push_back(Edge(from,to,cap,0));
        edges.push_back(Edge(to,from,0,0));
        m = edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }

    bool BFS()
    {
        memset(vis, 0, sizeof vis);
        queue<int> Q;
        Q.push(s);
        d[s] = 0;
        vis[s] = 1;
        while(!Q.empty())
        {
            int x = Q.front();
            Q.pop();
            for(int i = 0; i < G[x].size(); i++)
            {
                Edge &e = edges[G[x][i]];
                if(!vis[e.to]&&e.cap>e.flow)
                {
                    vis[e.to] = 1;
                    d[e.to] = d[x]+1;
                    Q.push(e.to);
                }
            }
        }
        return vis[t];
    }

    int DFS(int x,int a)
    {
        if(x==t||a==0) return a;
        int flow = 0, f;
        for(int &i = cur[x]; i < G[x].size(); i++)
        {
            Edge& e = edges[G[x][i]];
            if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0)
            {
                e.flow += f;
                edges[G[x][i]^1].flow -= f;
                flow += f;
                a -= f;
                if(a==0) break;
            }
        }
        return flow;
    }

    int Maxflow(int s,int t)
    {
        this->s = s, this->t = t;
        int flow = 0;
        while(BFS())
        {
            memset(cur, 0, sizeof cur);
            flow += DFS(s,INF);
        }
        return flow;
    }
};
vector<int> ans;
vector<int> dw;
int main()
{
    int n, m;
    while(scanf("%d%d",&n,&m)==2)
    {
        int s = 0, t = n+m+1;
        Dinic dinic;
        dinic.init(t+2);
        memset(in, 0, sizeof in);
        memset(out, 0, sizeof out);
        ans.clear();
        dw.clear();
        int G;
        for(int i = 1; i <= m; i++){
            scanf("%d",&G);
            dinic.AddEdge(i+n,t,INF);
            in[t]+=G;
            out[i+n]+=G;
        }
        int C, D, T, L, R;
        for(int i = 1; i <= n; i++){
            scanf("%d%d",&C,&D);
            dinic.AddEdge(s,i,D);
            for(int j = 1; j <= C; j++){
                scanf("%d%d%d",&T,&L,&R);
                T++;
                dinic.AddEdge(i,T+n,R-L);///T+n( ⊙ o ⊙ )啊!
                ans.push_back(dinic.edges.size()-2);
                dw.push_back(L);
                out[i]+=L;
                in[T+n]+=L;
            }
        }

        dinic.AddEdge(t,s,INF);

        int ss = t+1, tt = t+2;
        int sum = 0;
        for(int i = 1; i <= t; i++){
            if(in[i]>out[i]){
                sum += in[i]-out[i];
                dinic.AddEdge(ss,i,in[i]-out[i]);
            }
            if(in[i]<out[i]){
                dinic.AddEdge(i,tt,out[i]-in[i]);
            }
        }
        int flow = dinic.Maxflow(ss,tt);
        //cout<<"sum = "<<sum<<endl;
        //cout<<"flow = "<<flow<<endl;
        if(flow==sum){
            printf("%d\n",dinic.Maxflow(s,t));///这个就是最大流,但是下面的具体flow需要再加上 下界。
            for(int i = 0; i < ans.size(); i++){
                printf("%d\n",dinic.edges[ans[i]].flow+dw[i]);
            }
        }else
        {
            printf("-1\n");
        }
        printf("\n");
    }
    return 0;
}

 

posted on 2017-07-18 10:57  hnust_accqx  阅读(144)  评论(0编辑  收藏  举报

导航