您的位置:首页 > 其它

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的格点是黑色的,那么这是不是就是一个经典的模型了呢?不选之前枚举到的面上的点,其他的用行向列连边,跑二分图最大匹配就可以了。

/**************************************************************
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: