zoukankan      html  css  js  c++  java
  • 【CODEVS】1922 骑士共存问题

    算法】二分图最大匹配(最大流)

    【题解】按(i+j)奇偶性染色后,发现棋子跳到的地方刚好异色。

    然后就是二分图了,对于每个奇点向可以跳到的地方连边,偶点不需连(可逆)。

    所以题目要求转换为求二分图上最大独立集(对于每条边,至少有一个点不被选中)。

    最大独立集=总点数-最小割

    //代码略
    //hzwer's code:
    
    
    
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define INF 0x7fffffff
    using namespace std;
    int n,m,bl,wt,ans,cnt=1;
    bool del[201][201];
    int mark[201][201];
    int xx[8]={1,1,2,2,-1,-1,-2,-2},
        yy[8]={2,-2,1,-1,2,-2,1,-1};
    struct data{int to,next,v;}e[500001];
    int head[40002],h[40002];
    void insert(int u,int v,int w)
    {
         cnt++;
         e[cnt].to=v;
         e[cnt].next=head[u];
         head[u]=cnt;
         e[cnt].v=w;
         cnt++;
         e[cnt].to=u;
         e[cnt].next=head[v];
         head[v]=cnt;
     }
    void build()
    {
         for(int i=1;i<=n;i++)
             for(int j=1;j<=n;j++)
                 if(del[i][j])continue;
                 else if(mark[i][j]<bl)
                 {
                 for(int k=0;k<8;k++)
                 {
                         int nowx=i+xx[k],nowy=j+yy[k];
                         if(nowx<1||nowy<1||nowx>n||nowy>n||del[nowx][nowy])continue;
                         insert(mark[i][j],mark[nowx][nowy],INF);
                         }
                 insert(0,mark[i][j],1);
                 }
                 else insert(mark[i][j],wt,1);
     }
    bool bfs()
    {
         int q[40002],t=0,w=1,i,now;
         memset(h,-1,sizeof(h));
         h[0]=q[0]=0;
         while(t<w)
         {
                   now=q[t];t++;
                   i=head[now];
                   while(i)
                   {
                           if(h[e[i].to]==-1&&e[i].v){h[e[i].to]=h[now]+1;q[w++]=e[i].to;}
                           i=e[i].next;
                           }
                   }
         if(h[wt]==-1)return 0;
         return 1;
     }
    int dfs(int x,int f)
    {
        if(x==wt)return f;
        int i=head[x];
        int w,used=0;
        while(i)
        {
                if(e[i].v&&h[e[i].to]==h[x]+1)
                {
                    w=f-used;
                    w=dfs(e[i].to,min(w,e[i].v));   
                    e[i].v-=w;
                    e[i^1].v+=w;
                    used+=w;
                    if(used==f)return f;                      
                    }
                    i=e[i].next;
                }
        if(!used)h[x]=-1;
        return used;
        }
    void dinic(){while(bfs()){ans+=dfs(0,INF);}}
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
                int x,y;
                scanf("%d%d",&x,&y);
                del[x][y]=1;
                }
        bl=1,wt=(n*n+1)/2+1;
        for(int i=1;i<=n;i++)
           for(int j=1;j<=n;j++)
              if((i+j)%2==0){mark[i][j]=bl;bl++;}
              else {mark[i][j]=wt;wt++;}
        build();
        dinic();
        printf("%d",n*n-m-ans);
        return 0;
    }
    View Code
  • 相关阅读:
    关于注解
    关于泛型
    关于ER图和UML图之间的对比
    关于Eclipse中的egit的常规使用和模板
    关于Eclipse中的开源框架EMF(Eclipse Modeling Framework),第三部分
    关于Eclipse Modeling Framework进行建模,第二部分
    SQL Server 2005/2008备份数据库时提示“无法打开备份设备”
    试用版SQL Server 2008 R2 提示评估期已过
    该登录名来自不受信任的域,不能与 Windows 身份验证一起使用。
    SVN-如何删除 SVN 文件夹下面的小图标
  • 原文地址:https://www.cnblogs.com/onioncyc/p/6498555.html
Copyright © 2011-2022 走看看