飞行员配对方案
+ + + +
+
+
+ diff --git a/archives/index.html b/archives/index.html index d97893b..0b149cd 100644 --- a/archives/index.html +++ b/archives/index.html @@ -3,7 +3,7 @@
二分图匹配。
+设一个超级源点和一个超级汇点,建立源点->外籍飞行员->英国飞行员->汇点的网络。所有边的容量设为1。此时,每单位流到汇点的流量即代表一对合法配对,配对间互不干扰。
所以跑最大流即可得到最大匹配数。若想得到谁和谁配对的方案,则看看哪条边流量为0即可。
+#include <cstdio>
+#include <cstring>
+const int maxn=200+10;
+const int maxm=10000+10;
+const int INF=0x3f3f3f3f;
+int cur[maxn],head[maxn],nxt[maxm<<1],to[maxm<<1],val[maxm<<1];
+int dep[maxn];
+int n,m,s,t;
+int tot=1,cnt=0;
+struct edge
+{
+ int u,v;
+ edge() {}
+ edge(int x,int y) {u=x,v=y;}
+}e[maxm];
+struct Queue
+{
+ int a[maxn];
+ int l,r;
+ Queue() {l=1,r=0;}
+ void push(int x) {a[++r]=x;}
+ void pop() {l++;}
+ int front() {return a[l];}
+ bool empty() {return l>r;}
+}q;
+
+inline int min(int x,int y) {return x<y?x:y;}
+void add(int u,int v,int w)
+{
+ nxt[++tot]=head[u];
+ head[u]=tot;
+ to[tot]=v;
+ val[tot]=w;
+}
+bool bfs()
+{
+ memset(dep, 0x3f, sizeof(dep));
+ dep[s]=0;
+ q=Queue();
+ q.push(s);
+ while(!q.empty())
+ {
+ int u=q.front();
+ q.pop();
+ for (int i=head[u];i;i=nxt[i])
+ {
+ int v=to[i];
+ if (val[i]&&dep[v]>dep[u]+1)
+ {
+ dep[v]=dep[u]+1;
+ q.push(v);
+ }
+ }
+ }
+ return dep[t]<INF;
+}
+int dfs(int u,int minf)
+{
+ if (u==t)
+ return minf;
+ int used=0;
+ for (int &i=cur[u];i;i=nxt[i])
+ {
+ int v=to[i];
+ if (val[i]&&dep[v]==dep[u]+1)
+ {
+ int flow=dfs(v, min(minf-used, val[i]));
+ if (flow)
+ {
+ used+=flow;
+ val[i]-=flow;
+ val[i^1]+=flow;
+ if (used==minf)
+ break;
+ }
+ }
+ }
+ return used;
+}
+int main()
+{
+ scanf("%d%d",&m,&n);
+ s=0,t=m+n+1;
+ int u=-1,v=-1;
+ while(scanf("%d%d",&u,&v)&&u!=-1)
+ {
+ add(u, v, 1),add(v, u, 0);
+ e[++cnt]=edge(u, v);
+ }
+ for (int i=1;i<=m;i++)
+ add(s, i, 1),add(i, s, 0);
+ for (int i=m+1;i<=m+n;i++)
+ add(i, t, 1),add(t, i, 0);
+
+ int maxflow=0;
+ while(bfs())
+ {
+ for (int i=0;i<=m+n;i++)
+ cur[i]=head[i];
+ maxflow+=dfs(s, INF);
+ }
+ printf("%d\n",maxflow);
+ for (int i=1;i<=cnt;i++)
+ if (!val[i<<1])
+ printf("%d %d\n",e[i].u,e[i].v);
+ return 0;
+}
+
+
+ 建立超级源超级汇,建立源点->国际单位->圆桌->汇点的网络。其中,源点连边容量为(INF也可以,反正限制主要是后面),国际单位连边容量为1,圆桌连边容量为。跑出最大流即可得到最大匹配,与人数总数相比较即可知道是否有合法方案。方案统计只需对每个单位查询有哪些边的流量不为0即可。
+有一个小技巧是,先连国际单位->圆桌,后面统计时,查验边是否流量不为0的顺序就和存边时相等。由于同时存正反边(编号从2开始),第个单位和第个圆桌之间的边的编号即为。
+#include <cstdio>
+const int maxn=500;
+const int maxm=1e5;
+const int INF=0x3f3f3f3f;
+int cur[maxn],head[maxn],to[maxm<<1],nxt[maxm<<1],val[maxm<<1];
+int tot=1;
+int c[maxn],r[maxn];
+int s,t,n,m;
+int dep[maxn];
+struct Queue
+{
+ int a[maxn];
+ int l,r;
+ Queue() {l=1,r=0;}
+ void push(int x) {a[++r]=x;}
+ void pop() {l++;}
+ int front() {return a[l];}
+ bool empty() {return l>r;}
+}q;
+
+int min(int x,int y) {return x<y?x:y;}
+void add(int u,int v,int w)
+{
+ nxt[++tot]=head[u];
+ head[u]=tot;
+ to[tot]=v;
+ val[tot]=w;
+}
+bool bfs()
+{
+ for (int i=1;i<=n+m+1;i++)
+ dep[i]=INF;
+ q=Queue();
+ dep[s]=0;
+ q.push(s);
+ while(!q.empty())
+ {
+ int u=q.front();
+ q.pop();
+ for (int i=head[u];i;i=nxt[i])
+ {
+ int v=to[i];
+ if (val[i]&&dep[v]>dep[u]+1)
+ {
+ dep[v]=dep[u]+1;
+ q.push(v);
+ }
+ }
+ }
+ return dep[t]<INF;
+}
+int dfs(int u,int minf)
+{
+ if (u==t)
+ return minf;
+ int used=0;
+ for (int &i=cur[u];i;i=nxt[i])
+ {
+ int v=to[i];
+ if (val[i]&&dep[v]==dep[u]+1)
+ {
+ int flow=dfs(v, min(minf-used, val[i]));
+ if (flow)
+ {
+ used+=flow;
+ val[i]-=flow;
+ val[i^1]+=flow;
+ if (used==minf)
+ break;
+ }
+ }
+ }
+ return used;
+}
+int main()
+{
+ scanf("%d%d",&m,&n);
+ int sum=0;
+ for (int i=1;i<=m;i++)
+ scanf("%d",&r[i]),sum+=r[i];
+ for (int i=1;i<=n;i++)
+ scanf("%d",&c[i]);
+ for (int i=1;i<=m;i++)
+ for (int j=1;j<=n;j++)
+ add(i, m+j, 1),add(m+j, i, 0);
+
+ s=0,t=n+m+1;
+ for (int i=1;i<=m;i++)
+ add(s, i, r[i]),add(i, s, 0);
+ for (int i=1;i<=n;i++)
+ add(m+i, t, c[i]),add(t, m+i, 0);
+
+ int cnt=0;
+ while(bfs())
+ {
+ for (int i=0;i<=n+m;i++)
+ cur[i]=head[i];
+ cnt+=dfs(s, INF);
+ }
+ if (cnt<sum)
+ printf("0\n");
+ else
+ {
+ printf("1\n");
+ for (int i=1;i<=m;i++)
+ {
+ for (int j=1;j<=n;j++)
+ if (!val[((i-1)*n+j)<<1])
+ printf("%d ",j);
+ putchar('\n');
+ }
+ }
+ return 0;
+}
+
+
+