PowerOj 1736(网络流—最大流)

第二次世界大战时期,英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2名飞行员,其中1 名是英国飞行员,另1 名是外籍飞行员。在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英国飞行员很好地配合。如何选择配对飞行的飞行员才能使一次派出最多的飞机。对于给定的外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。对于给定的外籍飞行员与英国飞行员的配合情况,编程找出一个最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。

Input 

由文件input.txt提供输入数据。文件第1行有2个正整数mnn是皇家空军的飞行员总数(n<100)m是外籍飞行员数。外籍飞行员编号为1~m;英国飞行员编号为m+1~n。接下来每行有2个正整数ij,表示外籍飞行员i可以和英国飞行员j配合。文件最后以2-1结束。

Output 

程序运行结束时,将最佳飞行员配对方案输出到文件output.txt中。第1 行是最佳飞行员配对方案一次能派出的最多的飞机数M。接下来M行是最佳飞行员配对方案。每行有2个正整数ij,表示在最佳飞行员配对方案中,飞行员i和飞行员j配对。如果所求的最佳飞行员配对方案不存在,则输出‘No Solution!’

Sample Input

5 101 71 82 62 92 103 73 84 74 85 10-1 -1

Sample Output

41 72 93 85 10

EK代码:

#include

using namespace std;

const int maxn=105;

const int maxm=4004;

const int INF=0x3f3f3f3f;

int  head[maxn],pre[maxn],vis[maxn];

int n,m,tot=0;

inline int read()//输入外挂

{

  char ls=getchar();for (;ls<'0'||ls>'9';ls=getchar());

  int x=0;for (;ls>='0'&&ls<='9';ls=getchar())x=x*10+ls-'0';

  return x;

}

struct node

{

    int to,next,flow;//记录边,剩余流量

    node(){}

    node(int to,int next,int flow):to(to),next(next),flow(flow){}

}edge[maxm];

void init()

{

    tot=0;

    memset(head,-1,sizeof(head));

}

void add(int u,int v,int w)//有负边

{

    edge[tot]=node(v,head[u],w);//负边流量为w

    head[u]=tot++;

    edge[tot]=node(u,head[v],0);//起始点边流量为0

    head[v]=tot++;

}

int find_path(int st,int en)//实际上就是bfs搜出可以流的边

{

    memset(vis,0,sizeof(vis));

    queueq;

    q.push(st);

    vis[st]=1;//标记是否流过这条边,开始时候先让他流一次

    while(!q.empty())

    {

        int u=q.front();

        q.pop();

        if(u==en) return 1;//已经找到一条满足条件路径

        for(int i=head[u];~i;i=edge[i].next)

        {

            if(0==edge[i].flow) continue;//剩余流量为0

            int v=edge[i].to;

            if(!vis[v])

            {

                vis[v]=1;

                q.push(v);

                pre[v]=i;//记录前驱的边(正向边)

            }

        }

    }

    return 0;

}

int EK(int st,int en)

{

    int ans=0;

    while(find_path(st,en))

    {

        int flow=INF;

        for(int i=en;i!=st;i=edge[pre[i]^1].to)//倒着求,正向边是pre[i],那么反向边就是pre[i^1],当然要从0开始

        {

            flow=min(flow,edge[pre[i]].flow);//取剩余流量最小的

        }

        for(int i=en;i!=st;i=edge[pre[i]^1].to)

        {

            edge[pre[i]].flow-=flow;//由于倒着跑,所以正向边当然是减去

            edge[pre[i]^1].flow+=flow;//反向边当然就是加了

        }

        ans+=flow;

    }

    return ans;

}

int main()

{

    n=read();

    m=read();

    init();

    for(int i=1;i<=n;i++)add(0,i,1);//初始化流量都为1

    for(int i=n+1;i<=m;i++)add(i,m+1,1);//0-i,i-m+1建图

    int u,v;

    while(~scanf("%d%d",&u,&v))

    {

        if(u==-1&&v==-1) break;

        add(u,v,1);

    }

    int ans=EK(0,m+1);

    if(ans==0)

    {

        printf("NoSolution!\n");

        //break;

        return 0;

    }

    printf("%d\n",ans);

    for(int i=1;i<=n;i++)//n比较小,直接暴力找

    {

        for(int j=head[i];~j;j=edge[j].next)

        {

            if(edge[j].flow==0&&edge[j].to>n)

            {

                printf("%d%d\n",i,edge[j].to);

                break;

            }

        }

    }

    return 0;

}

dinic代码

 #include
using namespace std;
const int maxn = 100;
const int maxm = 4000;
struct EDGE
{
    int to, next, flow;
    EDGE(int to = 0, int next = 0, int flow = 0): to(to), next(next), flow(flow) {}
} edge[maxm];
int head[maxn], edgecnt;
void init()
{
    memset(head, -1, sizeof(head));
    edgecnt = 0;
}
void AddEdge(int s, int t, int c)
{
    edge[edgecnt] = EDGE(t, head[s], c);
    head[s] = edgecnt++;
    edge[edgecnt] = EDGE(s, head[t], 0);
    head[t] = edgecnt++;
}
int layer[maxn];
int p[maxn];
bool GetLayer(int st, int en)
{
    memset(layer, 0, sizeof(int) * (en + 1));
    layer[st] = 1;
    queueq;
    q.push(st);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        for(int i = head[u]; ~i; i = edge[i].next)
        {
            if(edge[i].flow == 0) continue;
            int v = edge[i].to;
            if(layer[v]) continue;
            layer[v] = layer[u] + 1;
            q.push(v);
        }
    }
    return layer[en];
}
int dfsFlow(int u, int en, int f)
{
    int ret = 0;
    if(u == en) return f;
    if(layer[u] >= layer[en]) return 0;
    for(; ~p[u]; p[u] = edge[p[u]].next)
    {
        if(edge[p[u]].flow == 0) continue;
        int v = edge[p[u]].to;
        if(layer[v] != layer[u] + 1) continue;
        int temp = dfsFlow(v, en, min(f, edge[p[u]].flow));
        ret += temp;
        f -= temp;
        edge[p[u]].flow -= temp;
        edge[p[u] ^ 1].flow += temp;
        if(f == 0) break;
    }
    return ret;
}
int dinic(int st, int en)
{
    int ans = 0;
    while(GetLayer(st, en))
    {
        memcpy(p, head, sizeof(int) * (en + 1));
        ans += dfsFlow(st, en, INT_MAX);
    }
    return ans;
}
int main()
{
    init();
    int n, m;
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= n; i++)
        AddEdge(0, i, 1);
    for(int i = n + 1; i <=  m; i++)
        AddEdge(i,  m + 1, 1);
    int u, v;
    while(scanf("%d %d", &u, &v), u != -1 && v != -1)
    {
        AddEdge(u, v, 1);
    }
    int ans = dinic(0,  m + 1);
    if(ans == 0)
    {
        printf("No Solution!");
        return 0;
    }
    printf("%d\n", ans);
    for(int i = 1; i <= n; i++)
        for(int j = head[i]; ~j; j = edge[j].next)
            if(edge[j].to > n && edge[j].flow == 0)
            {
                printf("%d %d\n", i, edge[j].to);
                break;
            }
    return 0;
}

你可能感兴趣的:(POWEROJ)