洛谷 P3254 圆桌问题 题解

原题题面

这题是网络流24题中难度较小的一道题,并没有什么思维难点

  1. 从源点向m个单位分别连边,流量为其人数

  2. 分别从n张桌子向汇点连边,流量为其容量

  3. m张桌子分别向n张桌子连边,流量为1(因为同一个单位来的代表不在同一个餐桌就餐。)

若最大流等于总人数,则有解,否则无解。

路径输出也不难,统计所有以单位为起点的边,若终点不为源点且为满流,就输出该边的终点。

附代码:

PS:为了使得输出和样例顺序一致,代码中使用了stack以逆序输出。

#ifndef ONLINE_JUDGE
#define _EXT_ENC_FILEBUF_H 1
#define _EXT_CODECVT_SPECIALIZATIONS_H 1
#endif // ONLINE_JUDGE
#include<bits/stdc++.h>
#include<bits/extc++.h>
using namespace std;
constexpr int Size=1e6+1,S=0,T=Size-2,Inf=INT_MAX;
struct edge{
	int v,w,nxt;
}e[Size];
int n,m,cnt=1;
long long sum;
int cur[Size],dep[Size],head[Size];
stack<int> ans;
int Dinic();
bool bfs();
int dfs(int u,int flow=Inf);
void add_edge(int u,int v,int w,bool flag=true);
inline int tbl(int pos){return pos+n;};
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1,flow;i<=n;i++){
		scanf("%d",&flow);
		sum+=flow;
		add_edge(S,i,flow);
	}
	for(int i=1,flow;i<=m;i++){
		scanf("%d",&flow);
		for(int j=1;j<=n;j++)
			add_edge(j,tbl(i),1);
		add_edge(tbl(i),T,flow);
	}
	if(Dinic()!=sum){
		putchar('0');
		exit(EXIT_SUCCESS);
	}
	puts("1");
	for(int i=1;i<=n;i++){
		for(int j=head[i];j;j=e[j].nxt)
			if(e[j].v!=S && e[j].w==0)
				ans.push(e[j].v-n);
		while(!ans.empty()){
			printf("%d ",ans.top());
			ans.pop();
		}
		putchar('\n');
	}
}
int Dinic()
{
    int ret=0;
    while(bfs()){
        memcpy(cur,head,sizeof(head));
        int d=dfs(S);
        while(d!=0){
            ret+=d;
            d=dfs(S);
        }
    }
    return ret;
}
int dfs(int u,int flow)
{
    if(u==T)
        return flow;
    for(int &i=cur[u];i;i=e[i].nxt)
        if(dep[e[i].v]==dep[u]+1&&e[i].w!=0){
            int di=dfs(e[i].v,min(flow,e[i].w));
            if(di<=0) continue;
            e[i].w-=di;
            e[i^1].w+=di;
            return di;
        }
    return 0;
}
bool bfs()
{
    queue<int> q;
    memset(dep,0,sizeof(dep));
    dep[S]=1;
    q.push(S);
    while(!q.empty()){
        int now=q.front();
        q.pop();
        for(int i=head[now];i;i=e[i].nxt)
            if(dep[e[i].v]==0&&e[i].w>0){
                dep[e[i].v]=dep[now]+1;
                q.push(e[i].v);
            }
    }
    return dep[T]>0;
}
void add_edge(int u,int v,int w,bool flag)
{
    cnt++;
    e[cnt].v=v;
    e[cnt].w=w;
    e[cnt].nxt=head[u];
    head[u]=cnt;
    if(flag) add_edge(v,u,0,false);
}
posted @ 2018-12-21 13:55  Saikbird  阅读(110)  评论(0编辑  收藏  举报