挑战NPC
2016-02-10 17:21
211 查看
挑战NPC
时间限制: 1 Sec 内存限制: 256 MB题目描述
传送门:http://uoj.ac/problem/171
ps.bzoj上的题面有毒,不用输出方案。
题解
神建图,orzvfk!!!把每个筐子拆成三个点,将这三个点相互连边(其实只要连一条就可以)。对于每个球,向能与它连边的所有筐子的每一个点连边,然后跑最大匹配即可。
先简单证明一下:如果一个筐子只放一个球或不放球,那么代表这个筐子的三个点就必定会有两个点形成一组匹配。若一个筐子放球数超过1个,则显然无法形成匹配。
最大匹配怎么写?不是二分图,匈牙利、网络流就行不通了。
别急,我们还有带花树(orzorz)!
至于带花树怎么写,网上资料很多,本蒟蒻就不再赘述了。
代码
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<cmath> #include<algorithm> #define N 610 #define M 200000 using namespace std; int T,n,m,e,ans,fa ,mate ,flag ,parent ; int k,la ,ff[M],l,r,q ,cnt,check ; struct node{int a,b;}map[M]; void add(int a,int b) { map[++k]=(node){a,b};ff[k]=la[a];la[a]=k; map[++k]=(node){b,a};ff[k]=la[b];la[b]=k; } int find(int x) { if(fa[x]==x)return x; return fa[x]=find(fa[x]); } int lca(int x,int y) { x=find(x);y=find(y);cnt++; while(1) { if(check[x]==cnt)return x; if(x)check[x]=cnt,x=find(parent[mate[x]]); if(check[y]==cnt)return y; if(y)check[y]=cnt,y=find(parent[mate[y]]); } } void merge(int x,int y,int t) { while(find(x)!=t) { parent[x]=y; if(flag[mate[x]]==2) q[r]=mate[x],flag[q[r]]=1,r++; if(find(x)==x)fa[x]=t; if(find(mate[x])==mate[x])fa[mate[x]]=t; y=mate[x];x=parent[y]; } } int bfs(int S) { for(int i=1;i<=n+m*3;i++)fa[i]=i,flag[i]=0; l=1;r=2;q[1]=S;flag[S]=1;parent[S]=0; while(l<r) { int x=q[l];l++; for(int a=la[x];a;a=ff[a]) { int y=map[a].b; if(!flag[y]) { parent[y]=x;flag[y]=2; if(!mate[y]) { while(y) { int t=mate[parent[y]]; mate[y]=parent[y]; mate[parent[y]]=y;y=t; } return 1; } q[r]=mate[y];flag[q[r]]=1;r++;continue; } if(flag[y]==1&&find(x)!=find(y)) { int t=lca(x,y); merge(x,y,t);merge(y,x,t); } } } return 0; } int main() { int a,b; scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&m,&e);ans=0; k=0;memset(la,0,sizeof(la)); memset(parent,0,sizeof(parent)); memset(mate,0,sizeof(mate)); for(int i=1;i<=e;i++) { scanf("%d%d",&a,&b); add(a,n+b);add(a,n+m+b);add(a,n+m*2+b); } for(int i=1;i<=m;i++)add(n+i,n+m+i); for(int i=1;i<=n+m*3;i++) if(!mate[i])ans+=bfs(i); printf("%d\n",ans-n); for(int i=1;i<=n;i++) { mate[i]-=n; if(mate[i]%m)printf("%d ",mate[i]%m); else printf("%d ",m); } printf("\n"); } return 0; }
相关文章推荐
- 数组名和数组名取地址& 的区别
- C++错误 C3861“getline”: 找不到标识符
- 前端笔记十二,表格、列表相关属性及media query
- hdoj 2067小兔的棋盘
- 如何读取maven项目中的resources
- Asp.net MVC中的ViewData与ViewBag
- HDU 2191 悼念512汶川大地震遇难同胞――珍惜现在,感恩生活2191
- Android EditText取消焦点并关闭输入法
- jquery.extend 函数详解
- 【CSS笔记】display:inline-block的使用
- hdu 1312 Red and Black
- 7.1、KNN实例
- Kali 2.0如何安装nvidia 340.XX驱动
- private Handler mHandler = new Handler() {...}是属于内部类
- JMX—标准MBean和模型MBean演示
- java基础之连接redis
- android多线程使用入门(简要笔记)
- Java中Reflection机制的初步理解(一)
- 代码段
- 代码段