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


    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3442

    题目大意:

    一个屌丝给m个女神拍照,计划拍照n天,每一天屌丝给给定的C个女神拍照,每天拍照数不能超过D张,而且给每个女神i拍照有数量限制[Li,Ri],对于每个女神n天的拍照总和不能少于Gi,如果有解求屌丝最多能拍多少张照,并求每天给对应女神拍多少张照;否则输出-1。

    解题思路:

    有源汇带上下界的最大流,我也是第一次写。

    说下建图:

    ①源点S到第i天流量为D[i]的边(上界为D[i],下界为0)

    ②第i天向女孩连流量为r-l的边(上界为r,下界为l)

    ③女孩向汇点T连流量为G[i]的边(上界为INF,下界为G[i])

    ④汇点向源点连流量为INF的边,使其变成无源汇图。(上界为INF,下界为0)

    ⑤out[i]为i点的出边下界和,in[i]为i点的入边下界和,若in[i]-out[i]>0,则从附加源点SS向i连流量为in[i]-out[i]的边,

    若in[i]-out[i]<0,则从i点向附加汇点TT连流量为out[i]-in[i]的边。

    具体求法,就是先求出改图是否存在可行流,即求有源汇上下界可行流,通过从T->连流量为INF的边即可将图变为无源汇图,这样就可以转换为无源汇上下界可行流求解。

    若存在可行流,则再求一次S->T的最大流即为答案。

    (这句话从网上找的)

    为什么呢?因为第一次SS->TT只是求得所有满足下界的流量,而残留网络(S,T)路上还有许多自由流(没有和超级源点和超级汇点连接的边)没有流满,所有最终得到的ans=(第一次流满下界的流+第二次能流通的自由流)。

    说起来ZOJ真是害我不浅啊,今天刚开始写上下界的题目,ZOJ 2314 low数组开小了一直TLE。。。。 然后这题忘记输出空行一直WA。。。 然后我每次都以为是自己写的问题debug好几个小时,难受啊。

    代码

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cmath>
      5 #include<algorithm>
      6 #include<queue>
      7 #include<vector>
      8 #define LL long long
      9 #define pii pair<int,int>
     10 #define pll pair<long long,long long>
     11 #define rep(i,a,b) for(int i=a;i<=b;i++)
     12 #define per(i,a,b) for(int i=a;i>=b;i--)
     13 #define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
     14 #define bug cout<<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"<<endl;
     15 #define bugc(_) cout << (#_) << " = " << (_) << endl;
     16 using namespace std;
     17 const int N=2e3+5;
     18 const int M=1e5+5;
     19 const int INF=0x3f3f3f3f;
     20 
     21 struct node{
     22     int to,next,flow;
     23 }edge[M*2];
     24 
     25 int cnt,st,en;
     26 int head[N],dep[N],out[N],in[N],low[M],G[N],D[N];
     27 
     28 void init(){
     29     cnt=2;
     30     memset(head,0,sizeof(head));
     31     memset(out,0,sizeof(out));
     32     memset(in,0,sizeof(in));
     33 }
     34 
     35 void link(int u,int v,int flow){
     36     edge[cnt]=node{v,head[u],flow};
     37     head[u]=cnt++;
     38     edge[cnt]=node{u,head[v],0};
     39     head[v]=cnt++;
     40 }
     41 
     42 int bfs(){
     43     memset(dep,0,sizeof(dep));
     44     dep[st]=1;
     45     queue<int>q;
     46     q.push(st);
     47     while(!q.empty()){
     48         int u=q.front();
     49         q.pop();
     50         for(int i=head[u];i;i=edge[i].next){
     51             node t=edge[i];
     52             if(t.flow&&!dep[t.to]){
     53                 dep[t.to]=dep[u]+1;
     54                 q.push(t.to);
     55             }
     56         }
     57     }
     58     return dep[en];
     59 }
     60 
     61 int dfs(int u,int fl){
     62     if(en==u) return fl;
     63     int tmp=0;
     64     for(int i=head[u];i&&fl;i=edge[i].next){
     65         node &t=edge[i];
     66         if(t.flow&&dep[t.to]==dep[u]+1){
     67             int x=dfs(t.to,min(t.flow,fl));
     68             if(x>0){
     69                 tmp+=x;
     70                 fl-=x;
     71                 t.flow-=x;
     72                 edge[i^1].flow+=x;
     73             }
     74         }
     75     }
     76     if(!tmp) dep[u]=-2;
     77     return tmp;
     78 }
     79 
     80 int dinic(int S,int T){
     81     st=S,en=T;
     82     int ans=0;
     83     while(bfs()){
     84         while(int d=dfs(st,INF))
     85             ans+=d;
     86     }
     87     return ans;
     88 }
     89 
     90 int main(){
     91     int n,m;
     92     while(~scanf("%d%d",&n,&m)){
     93         init();
     94         int S=0,T=n+m+1,SS=n+m+2,TT=n+m+3;
     95         for(int i=1;i<=m;i++) scanf("%d",&G[i]);
     96         int num=0,sum=0;
     97         for(int i=1;i<=n;i++){
     98             int C;
     99             scanf("%d%d",&C,&D[i]);
    100             for(int j=1;j<=C;j++){
    101                 int id,l,r;
    102                 scanf("%d%d%d",&id,&l,&r);
    103                 id++;
    104                 link(i,id+n,r-l);
    105                 low[++num]=l;
    106                 out[i]+=l;
    107                 in[id+n]+=l;
    108             }
    109         }
    110         link(T,S,INF);
    111         for(int i=1;i<=n;i++){
    112             link(S,i,D[i]);     //D[i]是上限,下限为0,因为每天最多拍D[i]张照片 
    113         }
    114         for(int i=1;i<=m;i++){
    115             link(i+n,T,INF);//G[i]是下限,因为每个人至少要G[i]张照片 
    116             in[T]+=G[i];
    117             out[i+n]+=G[i];
    118         }
    119         for(int i=0;i<=n+m+1;i++){
    120             int tmp=in[i]-out[i];
    121             if(tmp>0)    link(SS,i,tmp),sum+=tmp;
    122             else if(tmp<0)    link(i,TT,-tmp);
    123         }
    124         int ans=dinic(SS,TT);
    125         if(ans==sum){
    126             ans=dinic(S,T);
    127             printf("%d
    ",ans);
    128             for(int i=1;i<=num;i++){
    129                 printf("%d
    ",edge[i*2+1].flow+low[i]);
    130             }
    131         }
    132         else
    133             puts("-1");
    134         puts("");
    135     }
    136     return 0;
    137 }
  • 相关阅读:
    Python为什么要self
    安全散列算法(secure hash algorithm,SHA)
    傅里叶变换

    K 最近邻(k-nearest neighbours,KNN)算法
    贪婪算法
    狄克斯特拉算法
    广度优先搜索
    快速排序
    选择排序
  • 原文地址:https://www.cnblogs.com/fu3638/p/9895307.html
Copyright © 2020-2023  润新知