BZOJ3140 HNOI2013消毒
2016-01-16 00:58
417 查看
传送门
这道题有毒
我在做的时候就在想有没有一个什么“三分图”的匹配?(脑洞打开)
发现想不出来了,有观察到a,b,c中最小的最大只有17(a∗b∗c==5000)=>(min(a,b,c)<=50001/3)就又写起了搜索……(因为每一次肯定可以通过选取1*x*y的一块矩形,最终得到最优解)
最后一分没有,所有数据都是踩着边界给的……
然后看了题解,因为a,b,c中最小的不超过17,那么,我们可以枚举这17块的选与不选,再把剩下的拿来跑二分图匹配。剩下的怎么建图呢?我们想象我们可以透视,从最上面向下看,有1的格点是黑色的,那么这是不是就是一个经典的模型了呢?不选之前枚举到的面上的点,其他的用行向列连边,跑二分图最大匹配就可以了。
这道题有毒
我在做的时候就在想有没有一个什么“三分图”的匹配?(脑洞打开)
发现想不出来了,有观察到a,b,c中最小的最大只有17(a∗b∗c==5000)=>(min(a,b,c)<=50001/3)就又写起了搜索……(因为每一次肯定可以通过选取1*x*y的一块矩形,最终得到最优解)
最后一分没有,所有数据都是踩着边界给的……
然后看了题解,因为a,b,c中最小的不超过17,那么,我们可以枚举这17块的选与不选,再把剩下的拿来跑二分图匹配。剩下的怎么建图呢?我们想象我们可以透视,从最上面向下看,有1的格点是黑色的,那么这是不是就是一个经典的模型了呢?不选之前枚举到的面上的点,其他的用行向列连边,跑二分图最大匹配就可以了。
/************************************************************** Problem: 3140 User: geng4512 Language: C++ Result: Accepted Time:1180 ms Memory:1724 kb ****************************************************************/ #include<cstdio> #define MAXM 100005 #define MAXN 5005 struct node { int v, nxt; } e[MAXM]; int Adj[MAXN], n, ecnt, v[MAXN], A, B, C, tmp, MN, c[MAXN], tt; inline void Swap(int &a, int &b) { tmp = a; a = b; b = tmp; } struct Point { int x, y, z; inline void GET(int i, int j, int k) { x = i; y = j; z = k; if(A == MN) ; else if(B == MN) Swap(x, y); else Swap(x, z); } } p[MAXN]; inline void Add(int u, int v) { ++ ecnt; e[ecnt].v = v; e[ecnt].nxt = Adj[u]; Adj[u] = ecnt; } bool match(int u) { for(int i = Adj[u]; i; i = e[i].nxt) if(v[e[i].v] != tt) { v[e[i].v] = tt; if(!c[e[i].v] || match(c[e[i].v])) { c[e[i].v] = u; return 1; } } return 0; } int vis[MAXN], ans; void Buildmp() { ecnt = 0; for(int i = 1; i <= B; ++ i) Adj[i] = 0; for(int i = 1, a, b, c; i <= n; ++ i) { a = p[i].x; b = p[i].y; c = p[i].z; if(!vis[a]) Add(b, c); } } int Hungary(int lim, int ans) { //tt = 0; for(int i = 1; i <= C; ++ i) c[i] = 0; for(int i = 1; i <= B; ++ i) { ++ tt; if((ans += match(i)) >= lim) return lim; } return ans; } void dfs(int now, int cnt) { if(cnt >= ans) return; if(now > A) { Buildmp(); ans = Hungary(ans, cnt); return; } vis[now] = 1; dfs(now+1, cnt+1); vis[now] = 0; dfs(now+1, cnt); } int main() { int t, T; scanf("%d", &T); while(T --) { scanf("%d%d%d", &A, &B, &C); MN = A; (MN > B) && (MN = B); (MN > C) && (MN = C); n = 0; for(int i = 1; i <= A; ++ i) for(int j = 1; j <= B; ++ j) for(int k = 1; k <= C; ++ k) { scanf("%d", &t); if(t) p[++ n].GET(i, j, k); } if(A == MN) ; else if(B == MN) Swap(A, B); else Swap(A, C); ans = A; dfs(1, 0); printf("%d\n", ans); } return 0; }
相关文章推荐
- 快速掌握Lua 5.3 —— 函数
- hdoj-2049(不容易系列之(4)——考新郎)(全错位排列+排列组合)
- memcache
- MySQL详解--锁
- 【Go学习笔记】Hello Go!
- 复习 C++ 中类的函数指针
- G面经prepare: Friends Recommendation
- quick-cocos2dx-lua之精灵移动后的回调函数
- 对称加密算法DES,3重DES,TDEA,Blowfish,RC5,IDEA,AES。
- 对称加密算法DES,3重DES,TDEA,Blowfish,RC5,IDEA,AES。
- iOS小工具
- 万万没想到,公有云离中国影视特效渲染还有5年
- maven使用
- mysql概要(九)字符集和校对集
- 优秀前端工程师应该掌握的内容(转自:github)
- python学习笔记-Day11--paramiko
- BZOJ3139 HNOI2013比赛 (搜索)
- BZOJ3139 HNOI2013比赛 (搜索)
- virsh基于KVM创建虚拟机
- 最经典的Linux内核学习方法论