• 【集训试题】exam 信心考 最小割


    题意概述:

      有N个人,A,B两个考场。如果学生i在A考场,总信心值增加xi;如果学生i在B考场,总信心值增加yi。其中还有m对好友,当第i对好友的两个人都在A考场时,总信心值增加ai;如果两人都在B考场,总信心值增加bi;如果两个人在不同考场,那么总信心值减少ci。

      问总信心值最大能达到多少(总信心值的初始值为0)。

      N<=10000,M<=50000,time limit = 1s

    分析:

      这类最小割问题非常经典,一般都是有两个集合,每个元素属于某个集合可以得到某种收益,同时还会有一些两个元素之间的关系,比如被分到同一个集合或者不同集合需要付出的代价/得到的收益等等。思路是首先我们将所有的收益全部加起来,假设我们得到了所有的收益,然后建图跑最小割求我们需要付出的最小代价,最大收益=所有可能的收益-最小代价。

      说一下此题的建图,此题本身选择就可能产生代价,因此把代价看成收益。假设我们一开始从获得的总收益为,所有的x,y,a,b,c的和。

      令s代表B考场,t代表A考场,s向所有考生连边容量为yi,当这条边被割掉的时候考生i被选入A考场,付出代价yi;所有考生向t连一条边容量为xi,意义同上;所有的朋友之间,s向两个点分别连边,容量为(b+c)/2,当这两条边被一起割掉的时候他们都在A考场,付出代价b+c;两个点向t连边,意义类似;两个点之间连一条容量为(a+b+2c)/2,当两个考生在不同考场的时候(在网络意义下他们不连通)这条边被割掉,这对朋友一共付出代价a+b+2c。

      跑最小割即可,因为建图的时候涉及到除以二的问题所以先把所有的边容量乘以2,最后把这个2除回来即可。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cstdlib>
      5 #include<algorithm>
      6 #include<cmath>
      7 #include<queue>
      8 #include<set>
      9 #include<map>
     10 #include<vector>
     11 #include<cctype>
     12 #define inf 9e18 
     13 using namespace std;
     14 const int maxn=10005;
     15 const int maxm=50005;
     16 typedef long long LL;
     17 
     18 int N,M,A[maxn],B[maxn],S,T,tot;
     19 struct data{ int u,v,a,b,c; }C[maxm];
     20 struct net_edge{ int from,to,next; LL cap,flow; }NE[4*maxn+10*maxm];
     21 int nfirst[maxn],nnp,cur[maxn],fl[maxn],d[maxn],gap[maxn];
     22 int mq[maxn],front,rear;
     23 
     24 void _scanf(int &x)
     25 {
     26     x=0;
     27     char ch=getchar();
     28     while(ch<'0'||ch>'9') ch=getchar();
     29     while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
     30 }
     31 void data_in()
     32 {
     33     _scanf(N);_scanf(M);
     34     for(int i=1;i<=N;i++) _scanf(A[i]);
     35     for(int i=1;i<=N;i++) _scanf(B[i]);
     36     for(int i=1;i<=M;i++){
     37         _scanf(C[i].u);_scanf(C[i].v);
     38         _scanf(C[i].a);_scanf(C[i].b);_scanf(C[i].c);
     39     }
     40 }
     41 void net_add_edge(int u,int v,LL cap)
     42 {
     43     NE[++nnp]=(net_edge){u,v,nfirst[u],cap,0};
     44     nfirst[u]=nnp;
     45     NE[++nnp]=(net_edge){v,u,nfirst[v],0,0};
     46     nfirst[v]=nnp;
     47 }
     48 void _net_add_edge(int u,int v,LL cap)
     49 {
     50     NE[++nnp]=(net_edge){u,v,nfirst[u],cap,0};
     51     nfirst[u]=nnp;
     52     NE[++nnp]=(net_edge){v,u,nfirst[v],cap,0};
     53     nfirst[v]=nnp;
     54 }
     55 void build_net()
     56 {
     57     S=N+1,T=N+2,tot=T;
     58     for(int i=1;i<=N;i++){
     59         net_add_edge(S,i,(LL)2*B[i]);
     60         net_add_edge(i,T,(LL)2*A[i]);
     61     }
     62     int u,v;
     63     for(int i=1;i<=M;i++){
     64         u=C[i].u,v=C[i].v;
     65         net_add_edge(S,u,(LL)C[i].b+C[i].c);
     66         net_add_edge(u,T,(LL)C[i].a+C[i].c);
     67         net_add_edge(S,v,(LL)C[i].b+C[i].c);
     68         net_add_edge(v,T,(LL)C[i].a+C[i].c);
     69         _net_add_edge(u,v,(LL)C[i].a+C[i].b+(LL)2*C[i].c);
     70     }
     71 }
     72 void BFS(int s)
     73 {
     74     for(int i=1;i<=tot;i++) d[i]=tot;
     75     front=rear=0;
     76     mq[rear++]=s;
     77     d[s]=0;
     78     int i,j;
     79     while(front!=rear){
     80         i=mq[front++];
     81         for(int p=nfirst[i];p;p=NE[p].next){
     82             j=NE[p].to;
     83             if(d[j]==tot) d[j]=d[i]+1,mq[rear++]=j;
     84         }
     85     }
     86 }
     87 LL augment(int s,int t)
     88 {
     89     int now=t; LL flow=inf;
     90     while(now!=s){
     91         flow=min(flow,NE[fl[now]].cap-NE[fl[now]].flow);
     92         now=NE[fl[now]].from;
     93     }
     94     now=t;
     95     while(now!=s){
     96         NE[fl[now]].flow+=flow,NE[(fl[now]-1^1)+1].flow-=flow;
     97         now=NE[fl[now]].from;
     98     }
     99     return flow;
    100 }
    101 LL ISAP(int s,int t)
    102 {
    103     memcpy(cur,nfirst,sizeof(cur));
    104     BFS(t);
    105     for(int i=1;i<=tot;i++) gap[d[i]]++;
    106     LL maxflow=0; int now=s,j;
    107     while(d[s]<tot){
    108         if(now==t){
    109             maxflow+=augment(s,t);
    110             now=s;
    111         }
    112         bool ok=0;
    113         for(int p=cur[now];p;p=NE[p].next){
    114             j=NE[p].to;
    115             if(d[j]+1==d[now]&&NE[p].cap>NE[p].flow){
    116                 ok=1;
    117                 cur[now]=fl[j]=p;
    118                 now=j;
    119                 break;
    120             }
    121         }
    122         if(!ok){
    123             int minl=tot;
    124             for(int p=nfirst[now];p;p=NE[p].next){
    125                 j=NE[p].to;
    126                 if(d[j]+1<minl&&NE[p].cap>NE[p].flow) minl=d[j]+1;
    127             }
    128             if(--gap[d[now]]==0) break;
    129             gap[d[now]=minl]++;
    130             cur[now]=nfirst[now];
    131             if(now!=s) now=NE[fl[now]].from;
    132         }
    133     }
    134     return maxflow;
    135 }
    136 void work()
    137 {
    138     build_net();
    139     LL sum=0;
    140     for(int i=1;i<=N;i++) sum+=A[i],sum+=B[i];
    141     for(int i=1;i<=M;i++)
    142         sum+=C[i].a,sum+=C[i].b,sum+=C[i].c;
    143     cout<<sum-ISAP(S,T)/2<<'
    ';
    144 }
    145 int main()
    146 {
    147     data_in();
    148     work();
    149     return 0;
    150 }
    View Code
  • 相关阅读:
    抓包之网络分析器- Wiresshark
    IT 技术网站收集
    XAMPP Apache + MariaDB + PHP + Perl
    http://101.132.165.115/
    LNMP 网站搭建
    10X Genomics : Single Cell Gene Expression
    PacBio下机数据如何看?
    光模块
    ubuntu 'yuan' update
    Perl 中 `cmd` 和system"cmd"的区别
  • 原文地址:https://www.cnblogs.com/KKKorange/p/8445839.html
Copyright © 2020-2023  润新知