传送门
显然网络流呀。
源点向所有有床位的连边
需要床位的向汇点连边
如果i可以睡j的床,i向j‘连边
裸题呀。
#include<cstring>
#include<cmath>
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#define inf 2100000000
#define N 105
using namespace std;
struct edge{
int from,to,v,next;
}e[10005];
int tot,cas,n,sum;
int head[N],a[N],b[N],c[N][N],dis[N],q[N],from[N];
inline void add(int x,int y,int u){
e[++tot].from=x;
e[tot].to=y;
e[tot].v=u;
e[tot].next=head[x];
head[x]=tot;
}
inline void ins(int x,int y,int u){
add(x,y,u);
add(y,x,0);
}
inline void build(){
memset(head,0,sizeof(head));
memset(from,0,sizeof(from));
tot=1;
sum=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if ((a[i]==0||(a[i]==1&&b[i]==0))&&a[j]&&c[i][j]) ins(i,j+n,1);
for (int i=1;i<=n;i++)
if (a[i]==0||(a[i]==1&&b[i]==0)){
sum++;
ins(n*2+1,i,1);
}
for (int i=1;i<=n;i++) if (a[i]) ins(i+n,n*2+2,1);
}
inline int spfa(){
for (int i=1;i<=n*2+2;i++) dis[i]=inf;
int h=0,t=1,x;
q[1]=n*2+1;
dis[n*2+1]=0;
while (h<t){
x=q[++h];
for (int i=head[x];i;i=e[i].next)
if (dis[e[i].to]==inf&&e[i].v){
dis[e[i].to]=dis[x]+1;
from[e[i].to]=i;
q[++t]=e[i].to;
}
}
if (dis[n*2+2]==inf) return 0;
return 1;
}
inline void del(){
sum--;
for (int i=from[n*2+2];i;i=from[e[i].from]){
e[i].v--;
e[i^1].v++;
}
}
int main(){
scanf("%d",&cas);
while (cas--){
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=n;i++) scanf("%d",&b[i]);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) scanf("%d",&c[i][j]);
for (int i=1;i<=n;i++) if (a[i]) c[i][i]=1;
build();
while (spfa()) del();
if (!sum) printf("^_^\n"); else printf("T_T\n");
}
}