• Shoot the Bullet ZOJ


    /**
    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
    ",dinic.Maxflow(s,t));///这个就是最大流,但是下面的具体flow需要再加上 下界。
                for(int i = 0; i < ans.size(); i++){
                    printf("%d
    ",dinic.edges[ans[i]].flow+dw[i]);
                }
            }else
            {
                printf("-1
    ");
            }
            printf("
    ");
        }
        return 0;
    }
  • 相关阅读:
    IM的扫码登录功能如何实现?一文搞懂主流的扫码登录技术原理
    IM“扫一扫”功能很好做?看看微信“扫一扫识物”的完整技术实现
    2020年了,Android后台保活还有戏吗?看我如何优雅的实现!
    P2P技术详解(三):P2P中的NAT穿越(打洞)方案详解(进阶分析篇)
    微信团队分享:极致优化,iOS版微信编译速度3倍提升的实践总结
    史上最通俗,彻底搞懂字符乱码问题的本质
    你知道,HTTPS用的是对称加密还是非对称加密?
    IM开发基础知识补课(七):主流移动端账号登录方式的原理及设计思路
    面视必备,史上最通俗计算机网络分层详解
    阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处
  • 原文地址:https://www.cnblogs.com/xiaochaoqun/p/7199296.html
Copyright © 2020-2023  润新知