题意:有N(1<=N<=1e5)个人要移民到M(1<=M<=10)个星球上,每个人有自己想去的星球,每个星球有最大承载人数。问这N个人能否移民成功。

分析:可以用最大流的思路求解该问题,新建源点和汇点,源点与人间加入弧,流量为他想去的星球之和;星球和汇点间加入弧,流量为其承载数量;人和星球间加入弧,流量无限。但是本题中N很大,M却很小,所以想去星球的编号组成的二进制数最多不超过1024,那么可以将N个人缩点。然后跑最大流,满流为N。

#include<iostream>
#include<stdio.h>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int MAXN =1e4+,maxm =1e6+;
const int INF=0x3f3f3f3f; struct ISAP{
int head[MAXN], nv, n, tot; //nv:编号修改的上限
int num[MAXN], d[MAXN], pre[MAXN], cur[MAXN], q[MAXN];
struct node{
int v, next, cap;
}edge[maxm];
void init(){
memset(head,-,sizeof(head));
tot=;
}
void AddEdge(int u, int v, int cap){
edge[tot].v=v;edge[tot].cap=cap;edge[tot].next=head[u];
head[u]=tot++;
edge[tot].v=u;edge[tot].cap=;edge[tot].next=head[v];
head[v]=tot++;
}
void bfs(int s,int t){
memset(num,,sizeof(num));
memset(d,-,sizeof(d));
int f1=, f2=, i;
q[f1++]=t;
d[t]=;
num[]=;
while(f1>=f2){
int u=q[f2++];
for(i=head[u];i!=-;i=edge[i].next){
int v=edge[i].v;
if(d[v]==-){
d[v]=d[u]+;
num[d[v]]++;
q[f1++]=v;
}
}
}
}
int isap(int s,int t){
memcpy(cur,head,sizeof(cur));
int flow=, i, u=pre[s]=s;
bfs(s,t);
while(d[s]<nv){
if(u==t){
int f=INF, pos;
for(i=s;i!=t;i=edge[cur[i]].v){
if(f>edge[cur[i]].cap){
f=edge[cur[i]].cap;
pos=i;
}
}
for(i=s;i!=t;i=edge[cur[i]].v){
edge[cur[i]].cap-=f;
edge[cur[i]^].cap+=f;
}
flow+=f;
if(flow>=n)
return flow;
u=pos;
}
for(i=cur[u];i!=-;i=edge[i].next)
if(d[edge[i].v]+==d[u]&&edge[i].cap) break;
if(i!=-){
cur[u]=i;
pre[edge[i].v]=u;
u=edge[i].v;
}
else{
if(--num[d[u]]==) break;
int mind=nv;
for(i=head[u];i!=-;i=edge[i].next){
if(mind>d[edge[i].v]&&edge[i].cap){
mind=d[edge[i].v];
cur[u]=i;
}
}
d[u]=mind+;
num[d[u]]++;
u=pre[u];
}
}
return flow;
}
}F; int vis[]; int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int S,T,N,M,u,v,tmp,k;
int op;
while(scanf("%d%d",&N,&M)==){
F.init();
k=;
memset(vis,,sizeof(vis));
for(int i=;i<=N;++i){
int x=;
for(int j=;j<=M;++j){
scanf("%d",&op);
x<<=;
x+=op; //转换为二进制状态
}
vis[x]++;
}
for(int i=;i<=;++i) if(vis[i]) k++; //记录缩点后点数
S=;T=k+M+; F.nv=k+M+,F.n = N;
int id=;
for(int i=;i<=;++i){
if(!vis[i]) continue;
id++;
int sta = i,cnt = vis[i];
for(int j=,t=;j<=sta;j<<=,t++){
if(j&sta) F.AddEdge(id,t+k,INF);
}
F.AddEdge(S,id,cnt);
}
for(int i=;i<=M;++i){
scanf("%d",&tmp);
F.AddEdge(i+k,T,tmp);
}
if(F.isap(S,T)==N) printf("YES\n");
else printf("NO\n");
}
return ;
}

还有一种做法是二分图多重匹配。二分图多重匹配的思路与匈牙利算法接近,也是从以匹配的点中寻找增广路。X部为N个人,Y部为M个星球,每个星球有自己的匹配上限。在时间上,两种实现方法所差不多。

#include<iostream>
#include<stdio.h>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long LL;
const int maxn = 1e5+,maxm = 2e6+;
int N,M;
struct Node{
int K[];
}link[maxn];
int cnt[];
struct Edge{
int to,next;
}edges[maxm];
int head[maxn],tot;
bool used[];
int limit[]; void init()
{
tot=;
memset(head,-,sizeof(head));
} void AddEdge(int u,int v)
{
edges[tot].to = v;
edges[tot].next = head[u];
head[u] = tot++;
} bool dfs(int u){
int v;
for(int i=head[u];~i;i = edges[i].next){
v = edges[i].to;
if(!used[v]){
used[v]=true;
if(cnt[v]<limit[v]){
link[v].K[cnt[v]++]=u;
return true;
}
for(int j=;j<cnt[v];++j){
if(dfs(link[v].K[j])){
link[v].K[j]=u;
return true;
}
}
}
}
return false;
} bool hungary(){
memset(cnt,,sizeof(cnt));
for(int u=;u<=N;u++){
memset(used,,sizeof(used));
if(!dfs(u)) return false; //只要有一个人不能匹配则失败
}
return true;
} int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int T,u,v,tmp,k;
int op;
while(scanf("%d%d",&N,&M)==){
init();
for(int i=;i<=N;++i){
for(int j=;j<=M;++j){
scanf("%d",&op);
if(op) AddEdge(i,j);
}
}
for(int i=;i<=M;++i) scanf("%d",&limit[i]);
if(hungary()) printf("YES\n");
else printf("NO\n");
}
return ;
}

HDU - 3605 Escape (缩点+最大流/二分图多重匹配)的更多相关文章

  1. M - Escape - HDU 3605 - (缩点+最大流SAP)

    题目大意:2012世界末日来了,科学家发现了一些星球可以转移人口,不过有的人可以在一些星球上生存有的人不行,而且每个星球都有一定的承载量,现在想知道是否所有的人都可以安全转移呢? 输入:首先输入一个N ...

  2. Hdu 3605 Escape (最大流 + 缩点)

    题目链接: Hdu 3605  Escape 题目描述: 有n个人要迁移到m个星球,每个星球有最大容量,每个人有喜欢的星球,问是否所有的人都能迁移成功? 解题思路: 正常情况下建图,不会爆内存,但是T ...

  3. HDU 3605 Escape (网络流,最大流,位运算压缩)

    HDU 3605 Escape (网络流,最大流,位运算压缩) Description 2012 If this is the end of the world how to do? I do not ...

  4. HDU 3605 Escape(二分图多重匹配问题)

    Escape Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Subm ...

  5. hdu3605 Escape 二分图多重匹配/最大流

    2012 If this is the end of the world how to do? I do not know how. But now scientists have found tha ...

  6. hdu 3605(二分图多重匹配)

    Escape Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Subm ...

  7. HDU3605 Escape —— 二分图多重匹配

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3605 Escape Time Limit: 4000/2000 MS (Java/Others)    ...

  8. 【网络流24题】No.7 试题库问题 (最大流,二分图多重匹配)

    [题意] 假设一个试题库中有 n 道试题. 每道试题都标明了所属类别. 同一道题可能有多个类别属性.现要从题库中抽取 m 道题组成试卷.并要求试卷包含指定类型的试题. 试设计一个满足要求的组卷算法. ...

  9. 网络流24题 第五题 - PowerOJ1740 CodeVS1905 圆桌问题 二分图多重匹配 网络最大流

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - PowerOJ1740 - 有SPJ - 推荐 题目传送门 - CodeVS1905 - 无SPJ - 0% ...

随机推荐

  1. PAT002 Reversing Linked List

    题目: Given a constant K and a singly linked list L, you are supposed to reverse the links of every K ...

  2. Windows编程中回调函数的使用心得(MFC篇)

    回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数.回调函数不是由该函数的实现方直接调用,而是在特定 ...

  3. 【转】msxml 操作xml

    转自http://blog.csdn.net/dai_jing/article/details/8393392,原始出处不详. 1.简介 在.NET平台,微软为C#或托管C++程序员提供了丰富的类库, ...

  4. 天地币:所用到的 Android Socket 通讯编程技术试验

    1.为了开发"天地币"这个Android手机项目,须要用到Socket编程. 2.天地币是一种类似于比特币的虚拟货币. 3.为了赚取CSDN的C币,须要写篇博客. 4.干脆将调试S ...

  5. 边缘检测sobel算子

    sobel算子 - sophia_hxw - 博客园http://www.cnblogs.com/sophia-hxw/p/6088035.html #1,个人理解 网上查了很多资料,都说sobel算 ...

  6. CentOS安装Oracle官方JRE

    CentOS自带的JRE是OpenJDK,因为一些原因,需要换用Oracle官方出品的JRE. Oracle JRE下载地址http://java.com/zh_CN/(下载时注意选择相应版本) 可以 ...

  7. SurvivalShooter学习笔记(八.敌人管理器)

    敌人管理器:管理敌人的随机出生点创建 在场景中建立几个空物体,作为敌人的出生点 public class EnemyManager : MonoBehaviour { public PlayerHea ...

  8. Android 调用堆栈跟踪

    Android开发中,我们也会经常遇到段错误,也就是SIGSEGV(11),这个时候libc的backtrace会打印出对应的堆栈信 息,而你看到的仅仅是一对数字,好像无从查起. 如下面这一从串断错误 ...

  9. SSH原理记录

    一.什么是SSH? 简单说,SSH是一种网络协议,用于计算机之间的加密登录. 如果一个用户从本地计算机,使用SSH协议登录另一台远程计算机,我们就可以认为,这种登录是安全的,即使被中途截获,密码也不会 ...

  10. LeetCode-Integer Breaks

    Given a positive integer n, break it into the sum of at least two positive integers and maximize the ...