传送门
这个题想了很久。如何建图?
1. 有床的向汇点连边
2. 源点向需要床的连边,边权都为1
3. 跑最大流判断maxflow 是否和需要住宿的人tot相等即可
代码倒很简单,关键在于怎么想到的。(待更新)
相当于是一个 需要床的 和 有床的 一个匹配
还是自行参悟吧
#include
#include
#include
#include
#include
using namespace std;
const int maxn=1001;
const int inf=1e9;
queue <int> q;
int T,n,maxflow,tot;
struct Edge{
int next,to,dis;
}edge[maxn<<1];
int head[maxn],num_edge=-1,cur[maxn],deep[maxn];
bool sch[maxn],home[maxn];
void add_edge(int from,int to,int dis)
{
edge[++num_edge].next=head[from];
edge[num_edge].to=to;
edge[num_edge].dis=dis;
head[from]=num_edge;
}
bool bfs(int s,int t)
{
memset(deep,0x7f,sizeof(deep));
for (int i=0; i<=t; i++) cur[i]=head[i];
while (!q.empty()) q.pop();
deep[s]=0; q.push(s);
while (!q.empty())
{
int now=q.front(); q.pop();
for (int i=head[now]; i!=-1; i=edge[i].next){
int to=edge[i].to;
if (deep[to]>inf && edge[i].dis)
{
deep[to]=deep[now]+1;
q.push(to);
if (to==t) return true;
}
}
}
return deep[t]int dfs(int now,int t,int limit)
{
// printf("%d %d\n",now,limit);
if (now==t || !limit) return limit;
int flow=0,f;
for (int i=head[now]; i!=-1; i=edge[i].next)
{
cur[now]=i; int to=edge[i].to;
// printf("%d: %d %d %d\n",i,edge[i^1].to,to,edge[i].dis);
if (deep[to]==deep[now]+1 && (f=dfs(to,t,min(edge[i].dis,limit))))
{
// printf("f: %d %d\n",f,edge[i].to);
flow+=f;
limit-=f;
edge[i].dis-=f;
edge[i^1].dis+=f;
if (!limit) break;
}
}
return flow;
}
void Dinic(int s,int t)
{
while (bfs(s,t))
maxflow+=dfs(s,t,inf);
}
int main()
{
scanf("%d",&T);
int ans=0;
for (int i=1; i<=1e8+1e7; i++) ans++;
while (T--)
{
num_edge=-1; tot=0; maxflow=0;
memset(head,-1,sizeof(head));
scanf("%d",&n);
int s=0; int t=n*2+1;
for (int i=1; i<=n; i++)
{
scanf("%d",&sch[i]);//有床的向汇点连边
if (sch[i]) {add_edge(i+n,t,1); add_edge(t,i+n,0);}
}
for (int i=1; i<=n; i++)
{
scanf("%d",&home[i]);//源点向需要床的连边
if (!sch[i] || (sch[i]&&!home[i])) {tot++; add_edge(s,i,1); add_edge(i,s,0);}
}
for (int i=1; i<=n; i++)
for (int j=1; j<=n; j++)
{
int x; scanf("%d",&x);
if (x || i==j) {add_edge(i,j+n,1); add_edge(j+n,i,0);}
}
// for (int i=0; i<=num_edge; i++) printf("%d: %d %d %d\n",i,edge[i^1].to,edge[i].to,edge[i].dis);
Dinic(s,t);
if (maxflow==tot) printf("^_^\n");
else printf("T_T\n");
}
return 0;
}
注意节点的编号 +n 防止重复
S和T最好定义为变量,T应该为2*n+1 而不是 2*n,因这里WA掉了
By 中午在机房默写抄《烛之武退秦师》的LJXER