【BZOJ3140】消毒(HNOI2013)-二分圖匹配
阿新 • • 發佈:2018-12-13
測試地址:消毒 做法: 本題需要用到二分圖匹配。 挺妙的一道題,我反正是沒想出來。首先考慮二維的情況,即二維平面中有一些點,覆蓋一個的矩形所需要的代價是,求最小代價。 我們發現,直接覆蓋一個的矩形,並不比直接覆蓋條橫行或縱列優,因此最優解中一定是用一些橫行和縱列覆蓋,求最小代價就是很經典的二分圖最小點覆蓋問題了,轉化成求最大匹配即可。 但是現在有三維,用類似的討論可以將問題轉化為,用三種平面去覆蓋這些點(這裡平面指的就是某一維長度為,另外兩維無限長的立方體),但我們發現這個問題不能直接轉化成二分圖問題,而其他圖的覆蓋問題又是NP的,所以我們只能考慮列舉其中一種平面的選取。因為,所以,因此列舉最小那一維為的平面的選取情況有種。令最小的這一維為,列舉完這個後,我們發現另外兩種平面中,這一維都是無限長的,因此我們直接不管座標,而只考慮座標的覆蓋問題,這就是一個二維問題了,因此就用上面的二分圖匹配解決即可。複雜度比較玄幻,但原資料還是能輕鬆過的,BZOJ新增的資料需要卡點常。 (據加強資料的dalao說,有更優的,穩過的做法,但鑑於現在找不到這位大佬,所以只能這樣了,或者使用Dinic這樣的網路流做法來優化可能也行?) 以下是本人程式碼:
#include <bits/stdc++.h>
using namespace std;
int T,a,b,c,totp,l[20],r[20];
int first[10010],mat[10010],tot,tim=0;
struct point
{
int x,y,z;
}p[5010];
struct edge
{
int v,next;
}e[5010];
int vis[5010]={0};
void init()
{
totp=0;
scanf("%d%d%d",&a,&b,&c);
for(int i=1;i<=a;i++)
for(int j= 1;j<=b;j++)
for(int k=1;k<=c;k++)
{
int x;
scanf("%d",&x);
if (x) p[++totp].x=i,p[totp].y=j,p[totp].z=k;
}
if (a>b)
{
swap(a,b);
for(int i=1;i<=totp;i++)
swap(p[i].x,p[i].y);
}
if (a>c)
{
swap(a,c);
for(int i=1;i<=totp;i++)
swap(p[i].x,p[i].z);
}
if (b>c)
{
swap(b,c);
for(int i=1;i<=totp;i++)
swap(p[i].y,p[i].z);
}
}
bool cmp(point a,point b)
{
return a.x<b.x;
}
void insert(int a,int b)
{
e[++tot].v=b;
e[tot].next=first[a];
first[a]=tot;
}
int dfs(int v,int now)
{
if (vis[v]==now) return 0;
vis[v]=now;
for(int i=first[v];i;i=e[i].next)
if (!mat[e[i].v]||dfs(mat[e[i].v],now))
{
mat[e[i].v]=v;
return 1;
}
return 0;
}
void work()
{
sort(p+1,p+totp+1,cmp);
for(int i=1;i<=a;i++)
l[i]=r[i]=0;
for(int i=1;i<=totp;i++)
{
if (!l[p[i].x]) l[p[i].x]=i;
r[p[i].x]=i;
}
int finalans=1000000000;
for(int i=0;i<(1<<a);i++)
{
int x=i,ans=0;
for(int j=1;j<=b;j++)
first[j]=0;
for(int j=1;j<=c;j++)
mat[j]=0;
tot=0;
while(x)
{
if (x&1) ans++;
x>>=1;
}
for(int j=1;j<=totp;j++)
{
if (i&(1<<(p[j].x-1))) continue;
insert(p[j].y,p[j].z);
}
for(int j=1;j<=b;j++)
{
ans+=dfs(j,++tim);
if (ans>=finalans) break;
}
finalans=min(finalans,ans);
}
printf("%d\n",finalans);
}
int main()
{
scanf("%d",&T);
while(T--)
{
init();
work();
}
return 0;
}