• EZOJ 宝石迷阵 建图+网络流匹配


    题面:

      封印恶魔的地方可以看作是一个 n*m 的矩形,包含了 n*m 个祭坛,并且其 中有一些祭坛已经损坏了。

      如果 i+j 为偶数,那么第 i 行第 j 列的祭坛只要没有损坏,就一定会封印有一个恶魔。

       其他的没有损坏的祭坛可以用来放置魔法水晶,但是一个祭坛上只能放置一 个魔法水晶,并且一个魔法水晶只能向一个与它相邻的祭坛输送魔力,从而加固 封印。

       对于一个恶魔来说,如果与它相邻的两个成直角的水晶同时向它所在的祭坛 输送魔力的话,它就会被再次封印。 现在 Z 君想知道他最多可以封印多少恶魔?

    分析:

      这道题一眼看上去比较乱,但是其中的关系却很简单。

      若格子没有损坏,i+j为偶数则为恶魔,否则为魔法水晶,两个魔法水晶与一个恶魔相邻且成直角,就可以选择一起封印他。

      我们仔细一想:什么叫成直角!?!?说的那么文艺,实际上就是与同一个恶魔相邻的位于奇数列和偶数列的两个魔法水晶!

      那不就好办了?我们将奇数列和偶数列的魔法水晶分开来考虑,将恶魔拆成两个点,就形成了“一个人喜欢两类物品中的各一种,只能各选一种,问最多几人满意”这样的问题,于是就和我们上一篇中讨论的问题一样的了,拆点、连边、最大流、结束!

    代码:(我不知道为啥别人都写了一百大几十行……)

     1 #include<bits/stdc++.h>
     2 #define ms(a,x) memset(a,x,sizeof(a))
     3 using namespace std;int tot=0;
     4 const int N=10005,inf=0x3f3f3f3f;
     5 int S,T,q[N],h[N],c=1,n,m,k,d[N],cnt=0;
     6 int c1[55][55][2],fx[4]={1,0,-1,0};
     7 struct node{int y,z,nxt;}e[N*2];
     8 int fy[4]={0,1,0,-1};char s[55];
     9 bool isb(int i,int j){
    10     return c1[i][j][0]!=0;
    11 } bool isn(int i,int j){
    12     return ((i+j)&1);
    13 } void add(int x,int y,int z){
    14     e[++c]=(node){y,z,h[x]};h[x]=c;
    15     e[++c]=(node){x,0,h[y]};h[y]=c;
    16 } bool bfs(){
    17     int f=1,t=0;ms(d,-1);
    18     q[++t]=S;d[S]=0;
    19     while(f<=t){
    20         int x=q[f++];
    21         for(int i=h[x],y;i;i=e[i].nxt)
    22         if(d[y=e[i].y]==-1&&e[i].z)
    23         d[y]=d[x]+1,q[++t]=y;
    24     } return (d[T]!=-1);
    25 } int dfs(int x,int f){
    26     if(x==T) return f;int w,tmp=0;
    27     for(int i=h[x],y;i;i=e[i].nxt)
    28     if(d[y=e[i].y]==d[x]+1&&e[i].z){
    29         w=dfs(y,min(e[i].z,f-tmp));
    30         if(!w) d[y]=-1;
    31         e[i].z-=w;e[i^1].z+=w;
    32         tmp+=w;if(tmp==f) return f;
    33     } return tmp;
    34 } void dinic(){
    35     while(bfs()) tot+=dfs(S,inf);
    36 } int main(){
    37     scanf("%d%d",&n,&m);S=0;
    38     for(int i=1;i<=n;i++){
    39         scanf("%s",s+1);
    40         for(int j=1;j<=m;j++){
    41             if(s[j]=='X') continue;
    42             c1[i][j][0]=++cnt;
    43             if(!isn(i,j)) c1[i][j][1]=++cnt,
    44             add(c1[i][j][0],c1[i][j][1],1);
    45         }
    46     } T=++cnt;
    47     for(int i=1;i<=n;i++)
    48     for(int j=1;j<=m;j++){
    49         if(!isb(i,j)) continue;
    50         if(isn(i,j))
    51         for(int v=0;v<4;v++){
    52             int x=i+fx[v],y=j+fy[v];
    53             if(!isb(x,y)) continue;
    54             if(j&1) 
    55             add(c1[i][j][0],c1[x][y][0],1);
    56             else
    57             add(c1[x][y][1],c1[i][j][0],1);
    58         } if(isn(i,j)){
    59             if(j&1) add(S,c1[i][j][0],1);
    60             else add(c1[i][j][0],T,1);
    61         }
    62     } dinic();
    63     printf("%d
    ",tot);
    64     return 0;
    65 }
    拆点最大流
  • 相关阅读:
    java新手的session初体验
    菜鸟身份看泛型
    Java初学者不可不知的MyEclipse的设置技巧(自动联想功能)
    GCT之数学公式(几何部分)
    GCT之数学公式(代数部分)
    GCT之语文细节知识
    单元测试的方法
    常用的测试方法
    SQL 经典语句大全
    待处理(一)
  • 原文地址:https://www.cnblogs.com/Alan-Luo/p/10242465.html
Copyright © 2020-2023  润新知