zoukankan      html  css  js  c++  java
  • [网络流24题] 方格取数问题

    ~~~题面~~~

    题解:

    我们观察到题目要求相邻的格子只能选一个,那么我们能想到什么呢?

    最大点权独立集!

    但是怎么建图?

    我们首先对格子进行黑白染色,这样就构成了一个二分图,染色后连边。

    1,s ---> 白色, w = 权值

    2,黑色 ---> t , w = 权值

    3,白色 ---> 黑色 , w = inf

    连完之后跑网络流即可。

    ans = 权值和 - 最大流

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define AC 10000+200
      4 #define ACway 60000+600 //~~~~~~此处为了方便调试已经缩小一百倍,记得修改 
      5 int Head[AC],good[AC],have[AC],q[AC],head,tail,tot,s,t,m,M[110][110],n,x,ans,addflow,c[AC],last[AC],key;
      6 int date[ACway],Next[ACway],haveflow[ACway];
      7 bool co[110][110];
      8 int Min(int a,int b)
      9 {
     10     int c=(b-a)>>31;
     11     return (a&~c)|(b&c);
     12 }
     13 void add(int f,int w,int S)
     14 {
     15     //if(f==t&&w==s)printf("``%d
    ",tot);
     16 //    printf("@@%d %d %d
    ",f,w,s);
     17     date[++tot]=w;
     18     haveflow[tot]=S;
     19     Next[tot]=Head[f];
     20     Head[f]=tot;
     21 }
     22 int read()
     23 {
     24     int x=0;char c=getchar();
     25     while(c>'9'||c<'0')c=getchar();
     26     while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
     27     return x;
     28 }
     29 void pre()
     30 {
     31     int now;
     32     tot=1;
     33     n=read(),m=read();
     34     if(!(m%2))key=m+1;
     35     else key=m;//强行扩充为奇数列
     36     //要把整个图分成2个部分,一个放在前驱集合,一个放在后继集合,那么一共n*m+2个点
     37     s=n*key+1,t=n*key+2;
     38     for(int i=1;i<=n;i++)//读入并初始化ans
     39         for(int j=1;j<=m;j++)
     40         {
     41             M[i][j]=read();
     42             ans+=M[i][j];
     43         }
     44     for(int i=1;i<=n;i++)
     45         for(int j=1;j<=m;j++)
     46         {
     47             now=(i-1)*key+j;//(i-1)代表上面有多少行,所以应该要乘列数,然后加上这行的
     48             //printf("%d %d
    ",i,j);
     49             if(now%2)//因为是把整个图给分开了,所以点也是分成两部分,
     50             {
     51                 //由于将列数强行扩充到奇数,所以相邻的点奇偶性会不同
     52                 //又因为只有相邻才冲突,所以只有奇偶不同才连边,
     53                 //这里把奇数放在前驱集合,也就是说只有奇数会向外连边(防止重复)
     54                 if(i!=n)//如果不是最后一行就向下连边
     55                 {
     56                     add(now,now+key,INT_MAX);
     57                     add(now+key,now,0);
     58                 }
     59                 if(i!=1)
     60                 {
     61                     add(now,now-key,INT_MAX);
     62                     add(now-key,now,0);
     63                 }
     64                 if(j!=m)//如果不是最后一列就向右连边
     65                 {
     66                     add(now,now+1,INT_MAX);//仅仅起到连接作用,控制边权依靠s和t
     67                     add(now+1,now,0);
     68                 }
     69                  if(j!=1)//为防止漏边,是最后一列就向左连边,上同
     70                 {
     71                     add(now,now-1,INT_MAX);
     72                     add(now-1,now,0);
     73                 }
     74                 add(s,now,M[i][j]);//添加每个点和源点的连边
     75                 add(now,s,0);
     76             }
     77             else
     78             {
     79                 add(now,t,M[i][j]);//添加每个点和后继集合的连边
     80                 add(t,now,0);
     81             }
     82         }
     83 }
     84 void bfs()
     85 {
     86     int x=t,now;
     87     c[t]=1,q[++tail]=t,have[1]=1;
     88     memcpy(good,Head,sizeof(Head));
     89     while(head<tail)
     90     {
     91         x=q[++head];
     92         for(int i=Head[x]; i ;i=Next[i])
     93         {
     94             now=date[i];
     95             if(!c[now] && haveflow[i^1])
     96             {
     97                 c[now]=c[x]+1;
     98                 q[++tail]=now;
     99                 have[c[now]]++;
    100             }
    101         }
    102     }
    103 }
    104 void aru()
    105 {
    106  //   printf("%d <--- ",t);
    107     while(x!=s)
    108     {
    109         haveflow[last[x]]-=addflow;
    110         haveflow[last[x]^1]+=addflow;
    111         x=date[last[x]^1];
    112    //     printf("%d <--- ",x);
    113     }
    114   //  printf("the addflow is %d ",addflow);
    115    // printf("
    ");
    116     ans-=addflow;
    117 
    118 }
    119 void isap()
    120 {
    121     bool done;int now;
    122     x=s,addflow=INT_MAX;
    123     while(c[s]!=n*key+3)//~~~~~~~~记得修改
    124     {
    125         if(x==t)aru(),addflow=INT_MAX;
    126         done=false;
    127         for(int i=good[x]; i ;i=Next[i])
    128         {
    129             now=date[i];
    130             if(haveflow[i] && c[now]==c[x]-1)
    131             {
    132                 good[x]=i;
    133                 done=true;
    134                 addflow=Min(addflow,haveflow[i]);
    135                 last[now]=i;
    136                 x=now;
    137                 break;
    138             }
    139         }
    140         if(!done)
    141         {
    142             int go=n*key+2;//记得修改
    143             for(int i=Head[x]; i ;i=Next[i])//Head[x]!!!!!!!!!!!!!!!!!!!
    144             {
    145                 if(haveflow[i] && c[date[i]])go=Min(go,c[date[i]]);
    146             }
    147             good[x]=Head[x];
    148             if(!(--have[c[x]]))break;
    149             have[c[x]=go+1]++;
    150             if(x!=s)x=date[last[x]^1];
    151         }
    152     }
    153     printf("%d
    ",ans);
    154 }
    155 int main()
    156 {
    157     pre();
    158     bfs();
    159     isap();
    160    // printf("%d
    ",key);
    161     return 0;
    162 }
  • 相关阅读:
    git提交代码到远程仓库github
    git报错记录
    关于VSCode的一些设置
    css之列表数据前加上小方框
    EChats使用报错之 《"TypeError: Cannot read property 'getAttribute' of undefined"》
    EChats使用之给图表加箭头以及渐变
    vue报错之(Do not use v-for index as key on <transition-group> children)
    在vue项目中使用mock模拟数据
    Vue项目中关于EChats的使用
    使用mock数据实现登录时的一次bug记录
  • 原文地址:https://www.cnblogs.com/ww3113306/p/9367086.html
Copyright © 2011-2022 走看看