zoukankan      html  css  js  c++  java
  • [WC2016]挑战NPC 解题报告

    [WC2016]挑战NPC

    题意

    (n) 个球, (m) 个筐, (e) 个条件 ((u,v)), 表示球 (u) 可以放进筐 (v) 里面.

    每个球都必须放进筐里, 每个筐最多可以放 (3) 个球, 如果一个筐里的球数不超过 (1), 则称这个筐是 半满 的.

    求最多能使多少个筐半满, 并输出方案.

    数据保证一定存在一种方案使得每个球都放进筐里.

    思路

    匹配问题.

    把一个看做三个只能放一个球的.

    一个筐要是 半满 的, 那它至少要有 (2) 个空着的篮.

    要使这两个篮空着, 那它们就不能和其他球匹配, 那就让它们互相匹配吧.

    所以把每个球看成一个点, 把每个筐看成三个点, 求个一般图的最大匹配就好了, 套个带花树的板子. (带花树 学习笔记)

    注意 : 由于每个球都必须放进筐里, 所以先以球为起点求增广路.

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int __=600+7;
    const int ___=200000+7;    // 记得算好总共有多少条边
    int T,n,m,e,col[__],pre[__],mat[__],fa[__],fp[__],sym,ans,bel[__],tota;
    int lst[__],nxt[___],to[___],tot;
    queue<int> q;
    void add(int x,int y){ nxt[++tot]=lst[x]; to[tot]=y; lst[x]=tot; }
    int find(int x){ return fa[x]==x ?x :fa[x]=find(fa[x]); }
    int Lca(int x,int y){
      sym++;
      while(1){
        if(x){
          x=find(x);
          if(fp[x]==sym) return x;
          else{ fp[x]=sym; x=pre[mat[x]]; }
        }
        swap(x,y);
      }
      return 0;
    }
    void con(int x,int y,int lca){
      while(find(x)!=lca){
        pre[x]=y; fa[x]=lca;
        y=mat[x];
        col[y]=1; q.push(y);
        mat[y]=x; fa[y]=lca;
        x=pre[y];
      }
    }
    bool aug(int x){
      for(int i=1;i<=tota;i++){ col[i]=pre[i]=0; fa[i]=i; }
      while(!q.empty()) q.pop();
      q.push(x); col[x]=1;
      while(!q.empty()){
        int u=q.front(); q.pop();
        for(int i=lst[u];i;i=nxt[i]){
          int v=to[i];
          if(find(u)==find(v)||col[v]==2) continue;
          if(!col[v]){
    	pre[v]=u; col[v]=2;
    	if(!mat[v]){
    	  while(v){
    	    int t=mat[pre[v]];
    	    mat[v]=pre[v];
    	    mat[pre[v]]=v;
    	    v=t;
    	  }
    	  return 1;
    	}
    	else{ col[mat[v]]=1; q.push(mat[v]); }
          }
          else{
    	int lca=Lca(u,v);
    	con(u,v,lca); con(v,u,lca);
          }
        }
      }
      return 0;
    }
    int main(){
      //freopen("x.in","r",stdin);
      cin>>T;
      while(T--){
        scanf("%d%d%d",&n,&m,&e);
        int x,y; tot=ans=0; tota=n+3*m;
        memset(lst,0,sizeof(lst));
        memset(mat,0,sizeof(mat));
        for(int i=1;i<=e;i++){
          scanf("%d%d",&x,&y);
          add(x,y+n); add(y+n,x);
          add(x,y+n+m); add(y+n+m,x);
          add(x,y+n+m+m); add(y+n+m+m,x);
        }
        for(int i=1;i<=m;i++){
          add(i+n,i+n+m); add(i+n+m,i+n);
          add(i+n,i+n+m+m); add(i+n+m+m,i+n);
          add(i+n+m,i+n+m+m); add(i+n+m+m,i+n+m);
          bel[i+n]=bel[i+n+m]=bel[i+n+m+m]=i;
        }
        for(int i=1;i<=tota;i++){
          if(!mat[i]) ans+=aug(i);
        }
        printf("%d
    ",ans-n);
        for(int i=1;i<=n;i++) printf("%d ",bel[mat[i]]); putchar('
    ');
      }
      return 0;
    }
    
  • 相关阅读:
    pycharm激活(JetBrains IDEA 系列产品通用xx方法(license server))
    纯css美化下拉框、复选框以及单选框样式并用jquery获取到其被选中的val
    字符串替换
    jquery 倒计时效果
    js 数字前自动补零
    css 常用的绝对定位元素水平垂直居中的方法
    webapp中绝对定位/固定定位与虚拟键盘冲突的问题
    css 兼容各种iPhone
    使用 position:sticky 实现粘性布局
    jquery判断点击鼠标左、中、右键事件
  • 原文地址:https://www.cnblogs.com/BruceW/p/12147215.html
Copyright © 2011-2022 走看看