P2055 [ZJOI2009]假期的宿舍(二分图&最大流)
Posted Harris-H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2055 [ZJOI2009]假期的宿舍(二分图&最大流)相关的知识,希望对你有一定的参考价值。
P2055 [ZJOI2009]假期的宿舍(二分图&最大流)
人和床的匹配,关键是建图。
首先在校且不回家的人 add(i,i)
然后如果i和j认识,并且j在学校,那么建边add(i,j)
然后对于(不在学校或者(在学校不回家的))人进行匹配。
时间复杂度: O ( n m ) O(nm) O(nm)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=55,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
const int hashmod[4] = 402653189,805306457,1610612741,998244353;
#define mst(a,b) memset(a,b,sizeof a)
#define db double
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define x first
#define y second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define ios ios::sync_with_stdio(false),cin.tie(nullptr)
void Print(int *a,int n)
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\\n",a[n]);
template <typename T> //x=max(x,y) x=min(x,y)
void cmx(T &x,T y)
if(x<y) x=y;
template <typename T>
void cmn(T &x,T y)
if(x>y) x=y;
struct node
int to,nt;
e[M];
int cnt,h[N];
int n;
void add(int u,int v)
e[++cnt]=v,h[u],h[u]=cnt;
int vis[N],mh[N];
int id;
bool find(int u)
for(int i=h[u];i;i=e[i].nt)
if(vis[e[i].to]==id) continue;
int v=e[i].to;
vis[v]=id;
if(!mh[v]||find(mh[v]))
mh[v]=u;
return true;
return false;
int in[N],ho[N];
int main()
int T;
scanf("%d",&T);
while(T--)
id = cnt = 0;
scanf("%d",&n);
mst(h,0);
mst(mh,0);
mst(vis,0);
rep(i,1,n) scanf("%d",&in[i]);
rep(i,1,n)
scanf("%d",&ho[i]);
if(in[i]&&!ho[i])
add(i,i);
rep(i,1,n)
rep(j,1,n)
int x;scanf("%d",&x);
if(x && in[j]) add(i,j);
int ok = 1;
rep(i,1,n)
if(!in[i]||(in[i]&&!ho[i]))
++id;
if(!find(i))
ok = 0;
break;
puts(ok?"^_^":"T_T");
return 0;
做法2:网络流
源点连需要床的人 i 。
汇点连学校的人。
如果i 和j认识,且 j在学校, i就连j的床。
注意N开两倍,因为 人和床都要标号。
时间复杂度: O ( n 2 m ) O(n^2m) O(n2m)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=105,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
const int hashmod[4] = 402653189,805306457,1610612741,998244353;
#define mst(a,b) memset(a,b,sizeof a)
#define db double
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define x first
#define y second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define IOS ios::sync_with_stdio(false),cin.tie(nullptr)
void Print(int *a,int n)
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\\n",a[n]);
template <typename T> //x=max(x,y) x=min(x,y)
void cmx(T &x,T y)
if(x<y) x=y;
template <typename T>
void cmn(T &x,T y)
if(x>y) x=y;
struct Dinic
//Dinic O(n^2m)
int n,m,st,ed;
int id(int x,int y)
return (x-1)*m+y;
struct edge
int to,nt;
ll w;
e[M];
int h[N],cur[N],cnt,dep[N];
void init(int _st,int _ed)
st=_st,ed=_ed;
cnt=1;mst(h,0);
Dinic(int _st=0,int _ed=0)init(_st,_ed);
void add(int u,int v)
e[++cnt]=v,h[u],1,h[u]=cnt;
e[++cnt]=u,h[v],0,h[v]=cnt;
ll dfs(int u,ll c) //search for augment path
if(u==ed) return c;
ll res=c;
for(int &i=cur[u];i;i=e[i].nt)
int v=e[i].to; ll w=e[i].w;
if(w&&dep[v]==dep[u]+1)
ll now=dfs(v,min(res,w));
if(!now) dep[v]=1;
else e[i].w-=now,e[i^1].w+=now,res-=now;
if(!res) return c;
return c-res;
bool bfs() //layer the graph
queue<int>q;q.push(st);mst(dep,0),dep[st]=1;
while(!q.empty())
int u=q.front();q.pop();cur[u]=h[u];
for(int i=h[u];i;i=e[i].nt)
int v=e[i].to;ll w=e[i].w;
if(w&&!dep[v]) dep[v]=dep[u]+1,q.push(v);
return dep[ed];
ll dinic()
ll s=0;
while(bfs()) s+=dfs(st,inf);
return s;
G;
int in[N],ho[N];
int main()
int T;
scanf("%d",&T);
while(T--)
int n;scanf("%d",&n);
int ed=2*n+1;
int sum = 0;
G.init(0,ed);
rep(i,1,n) scanf("%d",&in[i]);
rep(i,1,n)
scanf("%d",&ho[i]);
if(!in[i]||(in[i]&&!ho[i]))
sum++;
G.add(0,i);
if(in[i])
G.add(i+n,ed);
if(in[i]&&!ho[i])
G.add(i,i+n);
rep(i,1,n)
rep(j,1,n)
int x;scanf("%d",&x);
if(x&&in[j])
G.add(i,j+n);
int ok = G.dinic()==sum;
puts(ok?"^_^":"T_T");
return 0;
以上是关于P2055 [ZJOI2009]假期的宿舍(二分图&最大流)的主要内容,如果未能解决你的问题,请参考以下文章