zoukankan      html  css  js  c++  java
  • bzoj4873: [Shoi2017]寿司餐厅(最小割)

    传送门

    大佬们是怎么一眼看出这是一个最大权闭合子图的……大佬好强->这里

    1.把所有区间$(i,j)$看成一个点,如果权值大于0,则从$S$向他连边,容量为权值,否则从它向$T$连边,容量为权值的相反数

    2.对于区间$(i,j)$,向所有的寿司$i$到$j$连边,表示选这个区间这些寿司必须选

    3.对每一个寿司类型$w[i]$,为他们各自开一个点,向$T$连边,容量为$m*w[i]*w[i]$

    4.对每一个寿司向他们所属的类型$w[i]$连边,容量为$inf$,向$T$连边,容量为$w[i]$

    5.对于所有区间$(i,j)$,向区间$(i-1,j),(i,j-1)$连边,容量$inf$,表示选了大的必须选小的

    然后用总收益减去最小割就行了

      1 //minamoto
      2 #include<iostream>
      3 #include<cstdio>
      4 #include<cstring>
      5 #include<queue>
      6 #define inf 0x3f3f3f3f
      7 #define ll long long
      8 using namespace std;
      9 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
     10 char buf[1<<21],*p1=buf,*p2=buf;
     11 inline int read(){
     12     #define num ch-'0'
     13     char ch;bool flag=0;int res;
     14     while(!isdigit(ch=getc()))
     15     (ch=='-')&&(flag=true);
     16     for(res=num;isdigit(ch=getc());res=res*10+num);
     17     (flag)&&(res=-res);
     18     #undef num
     19     return res;
     20 }
     21 const int N=50005,M=2000005;
     22 int head[N],Next[M],ver[M],edge[M],tot=1;
     23 int dep[N],cur[N],S,T;
     24 queue<int> q;
     25 inline void add(int u,int v,int e){
     26     ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e;
     27     ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=0;
     28 }
     29 bool bfs(){
     30     while(!q.empty()) q.pop();
     31     for(int i=S;i<=T;++i) cur[i]=head[i];
     32     memset(dep,-1,sizeof(dep));
     33     q.push(S),dep[S]=0;
     34     while(!q.empty()){
     35         int u=q.front();q.pop();
     36         for(int i=head[u];i;i=Next[i]){
     37             int v=ver[i];
     38             if(dep[v]<0&&edge[i]){
     39                 dep[v]=dep[u]+1,q.push(v);
     40                 if(v==T) return true;
     41             }
     42         }
     43     }
     44     return false;
     45 }
     46 int dfs(int u,int limit){
     47     if(u==T||!limit) return limit;
     48     int flow=0,f;
     49     for(int i=cur[u];i;i=cur[u]=Next[i]){
     50         int v=ver[i];
     51         if(dep[v]==dep[u]+1&&(f=dfs(v,min(limit,edge[i])))){
     52             flow+=f,limit-=f;
     53             edge[i]-=f,edge[i^1]+=f;
     54             if(!limit) break;
     55         }
     56     }
     57     if(!flow) dep[u]=-1;
     58     return flow;
     59 }
     60 int dinic(){
     61     int flow=0;
     62     while(bfs()) flow+=dfs(S,inf);
     63     return flow;
     64 }
     65 int n,m,a[105],mp[105][105],id[105][105],cnt=0;
     66 int idw[1005];bool vis[1005];ll sum=0;
     67 void build(){
     68     S=0;
     69     for(int i=1;i<=n;++i)
     70     for(int j=1;j<=n;++j)
     71     id[i][j]=++cnt;
     72     for(int i=1;i<=n;++i)
     73     if(!vis[a[i]]) vis[a[i]]=1,idw[a[i]]=++cnt;
     74     T=cnt+n+1;
     75     memset(vis,0,sizeof(vis));
     76     for(int i=1;i<=n;++i)
     77     if(!vis[a[i]]) vis[a[i]]=1,add(idw[a[i]],T,m*a[i]*a[i]);
     78     for(int i=1;i<=n;++i)
     79     add(i+cnt,idw[a[i]],inf),add(i+cnt,T,a[i]);
     80     for(int i=1;i<=n;++i)
     81     for(int j=i;j<=n;++j){
     82         if(mp[i][j]>0){
     83             sum+=mp[i][j];
     84             add(S,id[i][j],mp[i][j]);
     85             add(id[i][j],i+cnt,inf);
     86             add(id[i][j],j+cnt,inf);
     87         }
     88         else if(mp[i][j]<0){
     89             add(id[i][j],T,-mp[i][j]);
     90             add(id[i][j],i+cnt,inf);
     91             add(id[i][j],j+cnt,inf);
     92         }
     93         if(i!=j){
     94             add(id[i][j],id[i+1][j],inf);
     95             add(id[i][j],id[i][j-1],inf);
     96         }
     97     }
     98 }
     99 int main(){
    100     //freopen("testdata.in","r",stdin);
    101     n=read(),m=read();
    102     for(int i=1;i<=n;++i) a[i]=read();
    103     for(int i=1;i<=n;++i)
    104     for(int j=i;j<=n;++j)
    105     mp[i][j]=read();
    106     build();
    107     printf("%lld
    ",sum-dinic());
    108     return 0;
    109 }
  • 相关阅读:
    python基础练习(七)列表、元组、字典遍历
    python基础练习(六)字典_练习
    python基础练习(五)元组_练习
    python基础练习(四)列表_练习
    滑动条设置为角度
    cell-元胞数组
    MATLAB 爬取天气预报数据
    正则表达式匹配
    函数检视
    相关分析(三)——如何在Excel中计算两个变量之间的相关系数?
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9571630.html
Copyright © 2011-2022 走看看