SP9761 SCPC11H - Dolls 题解
SCPC11H - Dolls 题解
做法分析
套娃/套矩阵,是很经典的最小路径覆盖(二分图)模型。
如果一个套娃能完全套在另一个套娃里面(其长宽高均小于另一个)这样我们把大套娃向小套娃连边。
每一组套完的套娃,都可以对应到图上的一条路径(可以只是个单点,就是啥也没法套,一个点也可以看作一条路径)而每个套娃只能套一次,说明每一个点就只能在一条路径里出现。
这就显而易见了,是一个最小路径覆盖(一定是有向无环图,如果不是则说明有套娃的大小出现歧义,很好理解)
算法分析
那么 DAG 的最小路径覆盖怎么做呢?我们把原图中的每个点拆成
AC Code
#include<cstdio>
#include<algorithm>
#include<queue>
#include<iostream>
#include<cstring>
#include<ctime>
using namespace std;
#define maxn 1005
#define inf 1000000000
int n,s,t;
struct bbb{
int x,y,z;
}b[20*maxn];
struct aaa{
int to,next,c;
}a[maxn*maxn*10];
int head[maxn],tot,d[maxn*20];
void init() {
memset(head,-1,sizeof(head));
tot=0;
}
bool bfs() {
queue<int> q;
q.push(s);
memset(d,-1,sizeof(d));
d[s]=0;
while(!q.empty()) {
// printf("qwq\n");
int u=q.front();
q.pop();
for(int i=head[u];~i;i=a[i].next) {
int v=a[i].to;
if(d[v]==-1&&a[i].c) {
d[v]=d[u]+1;
q.push(v);
}
}
}
return d[t]!=-1;
}
int dfs(int u,int flow) {
if(u==t)
return flow;
int res=0;
for(int i=head[u];~i;i=a[i].next) {
int v=a[i].to;
if(a[i].c&&d[v]==d[u]+1) {
int tmp=dfs(v,min(flow,a[i].c));
flow-=tmp;
res+=tmp;
a[i].c-=tmp;
a[i^1].c+=tmp;
if(!flow)
break;
}
}
if(!res)
d[u]=-1;
return res;
}
int Dinic() {
int res=0;
while(bfs())
res+=dfs(s,inf);
return res;
}
void add(int x,int y,int c) {
a[tot].to=y;
a[tot].c=c;
a[tot].next=head[x];
head[x]=tot++;
}
int main() {
clock_t c1=clock();
#ifdef LOCAL
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
#endif
//=========================================
while(scanf("%d",&n),n) {
init();
for(int i=1;i<=n;i++)
scanf("%d%d%d",&b[i].x,&b[i].y,&b[i].z);
s=0,t=2*n+2;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(b[i].x>b[j].x&&b[i].y>b[j].y&&b[i].z>b[j].z)
add(i,j+n,1),add(j+n,i,0);
for(int i=1;i<=n;i++)
add(s,i,1),add(i,s,0);
for(int i=1;i<=n;i++)
add(i+n,t,1),add(t,i+n,0);
printf("%d\n",n-Dinic());
}
//=========================================
end:
cerr<<"Tmie Used:"<<clock()-c1<<"ms"<<endl;
return 0;
}