[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\n",ans-n);
    for(int i=1;i<=n;i++) printf("%d ",bel[mat[i]]); putchar('\n');
  }
  return 0;
}

原文地址:https://www.cnblogs.com/brucew-07/p/12147215.html

时间: 2024-08-28 14:08:28

[WC2016]挑战NPC 解题报告的相关文章

BZOJ4405 [wc2016]挑战NPC

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/转载请注明出处,侵权必究,保留最终解释权! Description 小N最近在研究NP完全问题,小O看小N研究得热火朝天,便给他出了一道这样的题目: 有n个球,用整数1到n编号.还有m个筐子,用整数1到m编号. 每个筐子最多能装3个球. 每个球只能放进特定的筐子中.具体有e个条件,第i个条件用两个整

[WC2016]挑战NPC

Sol 这做法我是想不到\(TAT\) 每个筐子拆成三个相互连边 球向三个筐子连边 然后跑一般图最大匹配 这三个筐子间最多有一个匹配 那么显然每个球一定会放在一个筐子里,一定有一个匹配 如果筐子间有匹配,则有一个半空的筐子,因为它一定只匹配了小于等于\(1\)个球 答案为匹配数\(-n\) 使答案最大即匹配数最大 上带花树就好了 # include <bits/stdc++.h> # define RG register # define IL inline # define Fill(a,

UOJ171 【WC2016】挑战NPC

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/转载请注明出处,侵权必究,保留最终解释权! Description 小N最近在研究NP完全问题,小O看小N研究得热火朝天,便给他出了一道这样的题目: 有n个球,用整数1到n编号.还有m个筐子,用整数1到m编号. 每个筐子最多能装3个球. 每个球只能放进特定的筐子中.具体有e个条件,第i个条件用两个整

解题报告 之 POJ3057 Evacuation

解题报告 之 POJ3057 Evacuation Description Fires can be disastrous, especially when a fire breaks out in a room that is completely filled with people. Rooms usually have a couple of exits and emergency exits, but with everyone rushing out at the same time

第五届蓝桥杯软件大赛C/C++本科B组决赛解题报告

mnesia在频繁操作数据的过程可能会报错:** WARNING ** Mnesia is overloaded: {dump_log, write_threshold},可以看出,mnesia应该是过载了.这个警告在mnesia dump操作会发生这个问题,表类型为disc_only_copies .disc_copies都可能会发生. 如何重现这个问题,例子的场景是多个进程同时在不断地mnesia:dirty_write/2 mnesia过载分析 1.抛出警告是在mnesia 增加dump

leetCode解题报告5道题(七)

先送上亚马逊传送门:<黑客与画家>:硅谷创业之父 Paul Graham 文集 再送上一个思维导图: 最好的办法就是自己创业或者加入创业公司 一个命题 命题 创业是一个压缩的过程,所有工作压缩成短短几年. 你不再是低强度的工作四十年,而是以极限强度工作四年 举例解释 一个优秀的黑客去除各种障碍,工作效率可以是在公司时的36倍. 假设他年薪8万美元,那么一个勤奋工作,摆脱杂事干扰的聪明黑客, 他的工作相当于年薪200万美元的价值 这里说的是极限情况,休闲时间为0,工作强度足以危害到健康. 守恒定

Best Cow Line 解题报告

题目链接: http://poj.org/problem?id=3617 题意: 已知一段长度为N的字符串,让你构造一个字典序最小的字符串.构造的规则如下:如果原始字符串的头部 < 原始字符串的尾部,则从原始字符串的头部删除该字符添加到新         的字符串的一个字符;如果头部 > 尾部则删除尾部的字符添加到新字符串中. 解题思路: 首先用两个索引记录首尾的位置,然后依次比较两者的值,若头部的值小则头部索引+1向后移动一位,若尾部的值小则尾部索引-1向前移动一位,这是当两个位置的值不一样

解题报告 之 POJ3680 Intervals

解题报告 之 POJ3680 Intervals Description You are given N weighted open intervals. The ith interval covers (ai, bi) and weighs wi. Your task is to pick some of the intervals to maximize the total weights under the limit that no point in the real axis is c

CSU-ACM2014暑假集训基础组训练赛(1) 解题报告

•Problem A HDU 4450                 水题,签到题 水题..没啥好说的.给大家签到用的. 1 #include <cstdio> 2 int main(){ 3 int n,a,ans; 4 while(scanf("%d",&n),n){ 5 ans = 0; 6 for(int i = 0;i < n;i++){ 7 scanf("%d",&a); 8 ans += a*a; 9 } 10 pr