zoukankan      html  css  js  c++  java
  • [Aizu1410]Draw in Straight Lines

    注意到当操作确定后,显然操作顺序总是涂黑色的1操作->涂白色的1操作->2操作

    用$b/w_{r/c}(i,j)$表示$(i,j)$是否被黑色/白色 横着/竖着 涂过(1表示涂过,0表示没有),注意到当这些信息被确定后,已经可以确定是否可行以及对应的代价

    具体的,考虑一个格子$(i,j)$,对其进行分析——

    注意到$b_{r}(i,j)=w_{r}(i,j)=1$一定不优秀(严格,$c$类似),证明对其分三类讨论:

    1.若对应的两次操作不相互包含,则可以缩短黑色操作

    2.若其中白色操作包含黑色,则可以直接去掉黑色操作

    3.若其中黑色操作包含白色操作,则可以将黑色操作拆成两段并去掉白色操作(注意到白色操作覆盖的段已经被涂两次,不会再有别的操作)

    根据此性质,再对其颜色分类讨论:

    1.若其要求最终为黑色,则要求$w_{r}(i,j)=w_{c}(i,j)=0$,并且若$b_{r}(i,j)=b_{c}(i,j)=0$则还要用2操作涂黑(即额外产生$c$的代价),另外显然其一定不会被涂超过2次

    2.若其要求最终为白色,根据之前的性质即要求$b_{r}(i,j)and b_{c}(i,j)=0$,并且若$b_{r}(i,j)=1$且$w_{c}(i,j)=0$(或$b_{c}(i,j)=1$且$w_{r}(i,j)=0$)则还要用1操作涂白

    另外,还要求1操作的代价,关于$a$即每一个格子会产生$sum b/w_{r/c}(i,j)$个$a$的代价,关于$b$考虑操作的起点,也即对于$b_{r}(i,j)=1$且$b_{r}(i,j-1)=0$($w$和$c$类似)的格子会再产生$b$的代价

    关于这个问题,容易想到最小割,下面描述建图——

    对每一个$b/w_{r/c}(i,j)$建立一个点,从$S$向$b_{r}/w_{c}(i,j)$连边$,b_{c}/w_{r}(i,j)$向$T$连边(边权均为$a$,即割表示对应的值选1),进而在这个基础结构上,依次考虑上面的限制和代价:

    1.要求$b_{r}(i,j)$和$w_{r}(i,j)$($c$类似)不同时为1,那么从$w_{r}(i,j)$向$b_{r}(i,j)$连一条边权为$infty$的边即可

    2.要求最终为黑色的点$w_{r}(i,j)=w_{c}(i,j)=0$,那么从$w_{r/c}(i,j)$再向$T$连一条边权为$infty$的边即可

    3.若最终为黑色的点$b_{r}(i,j)=b_{c}(i,j)=0$则产生$c$的代价,那么从$b_{r}(i,j)$向$b_{c}(i,j)$连一条边权为$c$的边即可

    4.要求最终为白色的点$b_{r}(i,j)and b_{c}(i,j)=0$,那么从$b_{c}(i,j)$向$b_{r}(i,j)$连一条边权为$infty$的边即可

    5.若最终为白色的点$b_{r}(i,j)=1$且$w_{c}(i,j)=0$(另一种类似)则产生$c$的代价,那么从$w_{c}(i,j)$向$b_{r}(i,j)$连一条边权为$c$的边,注意到若$b_{r}(i,j)$没被割掉或$w_{c}(i,j)$被割掉该边显然不需要被割掉,同时当两者均不成立时(即所要求的情况)则$b_{r}(i,j)$必然存在一条路径,进而即会要求其被割掉

    6.若$b_{r}(i,j)=1$且$b_{r}(i,j-1)=0$则产生$b$的代价($w$和$c$类似),那么从$b_{r}(i,j-1)$向$b_{r}(i,j)$连一条边权为$b$的边,正确性与5类似(特别的,还需要从$S$再向$b_{r}(i,1)$连一条边权为$b$的边)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 45
     4 #define maxV N*N*4
     5 #define maxE N*N*30
     6 #define oo 0x3f3f3f3f
     7 struct Edge{
     8     int nex,to,len;
     9 }edge[maxE];
    10 queue<int>q;
    11 int n,m,V,E,a,b,c,ans,br[N][N],bc[N][N],wr[N][N],wc[N][N],head[maxV],work[maxV],d[maxV];
    12 char s[N][N];
    13 void add(int x,int y,int z){
    14     edge[E]=Edge{head[x],y,z};
    15     head[x]=E++;
    16     if (E&1)add(y,x,0);
    17 }
    18 bool bfs(){
    19     memset(d,oo,sizeof(d));
    20     d[0]=0,q.push(0);
    21     while (!q.empty()){
    22         int k=q.front();
    23         q.pop();
    24         for(int i=head[k];i!=-1;i=edge[i].nex)
    25             if ((edge[i].len)&&(d[edge[i].to]==oo)){
    26                 d[edge[i].to]=d[k]+1;
    27                 q.push(edge[i].to);
    28             }
    29     }
    30     return d[V]!=oo;
    31 }
    32 int dfs(int k,int s){
    33     if (k==V)return s;
    34     int ans=0;
    35     for(int &i=head[k];i!=-1;i=edge[i].nex)
    36         if ((edge[i].len)&&(d[edge[i].to]==d[k]+1)){
    37             int p=dfs(edge[i].to,min(s,edge[i].len));
    38             edge[i].len-=p,edge[i^1].len+=p,s-=p,ans+=p;
    39             if (!s)return ans;
    40         }
    41     return ans;
    42 }
    43 int main(){
    44     scanf("%d%d%d%d%d",&n,&m,&a,&b,&c);
    45     for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
    46     for(int i=1;i<=n;i++)
    47         for(int j=1;j<=m;j++){
    48             br[i][j]=++V,bc[i][j]=++V;
    49             wr[i][j]=++V,wc[i][j]=++V;
    50         }
    51     V++;
    52     memset(head,-1,sizeof(head));
    53     for(int i=1;i<=n;i++)
    54         for(int j=1;j<=m;j++){
    55             add(0,br[i][j],a),add(0,wc[i][j],a);
    56             add(bc[i][j],V,a),add(wr[i][j],V,a);
    57             add(wr[i][j],br[i][j],oo);
    58             add(bc[i][j],wc[i][j],oo);
    59             if (s[i][j]=='#'){
    60                 add(wr[i][j],V,oo),add(0,wc[i][j],oo);
    61                 add(br[i][j],bc[i][j],c);
    62             }
    63             else{
    64                 add(bc[i][j],br[i][j],oo);
    65                 add(wc[i][j],br[i][j],c);
    66                 add(bc[i][j],wr[i][j],c);
    67             }
    68             if (j==1)add(0,br[i][j],b),add(wr[i][j],V,b);
    69             else add(br[i][j-1],br[i][j],b),add(wr[i][j],wr[i][j-1],b);
    70             if (i==1)add(bc[i][j],V,b),add(0,wc[i][j],b);
    71             else add(bc[i][j],bc[i-1][j],b),add(wc[i-1][j],wc[i][j],b);
    72         }
    73     memcpy(work,head,sizeof(head));
    74     while (bfs()){
    75         ans+=dfs(0,oo);
    76         memcpy(head,work,sizeof(head));
    77     }
    78     printf("%d
    ",ans);
    79     return 0;
    80 }
    View Code
  • 相关阅读:
    vant -图片上传
    Android知识点:Integer.valueOf()
    Android知识点:getText().toString()
    Android多个点击事件监听简化编程方式:implements View.OnClickListener
    实际操作PC端串口调试助手软件与实际51单片机相互通信
    借助虚拟串口驱动软件模拟PC端串口调试助手软件与Proteus中51单片机相互通信来点亮熄灭LED灯
    借助虚拟串口驱动软件模拟PC端串口调试助手软件与Proteus中51单片机相互通信二
    借助虚拟串口驱动软件模拟PC端串口调试助手软件与Proteus仿真电路图中VIRTUAL TERMINAL相互通信
    借助虚拟串口驱动软件模拟PC端串口调试助手软件与Proteus中51单片机相互通信一
    PC端串口调试助手软件与Proteus中51单片机相互通信的单片机C语言程序
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15476197.html
Copyright © 2011-2022 走看看