NK 飞行员配对方案问题 网络流

http://acm.nankai.edu.cn/p2121.html

南开的24道网络流里的第一个  汉语题目  哈哈  

二分匹配,增加一个源点S  一个汇点T 然后按最大流算 dinic

下面用矩阵和链表加边做的,两种写法目前当模板了

(一)用矩阵存储 运行时间 0MS

代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<queue>
#include<cstring>
#define Min(a,b)a<b?a:b
#define inf 100000
using namespace std;
int map[102][102],level[102];
int m,n,SUM,mark;

int dfs(int x,int Cap)
{
    if(x==n+1)
        return Cap;

    int i,temp,tt,y=0;
    for(i=1;i<=n+1;i++)
    {
        if(level[i]==level[x]+1&&Cap>y&&map[x][i]>0)
        {
            temp=Min(Cap-y,map[x][i]);
            if(temp==0)continue;
            tt=dfs(i,temp);
            map[x][i]-=tt;
            map[i][x]+=tt;
            y+=tt;

        }
    }
    return y;
}

int bfs()
{
   int tt,k;
   queue<int>qu;
   memset(level,-1,sizeof(level));
   level[0]=0;
   qu.push(0);
   while(!qu.empty())
   {
       tt=qu.front();
       qu.pop();
       for(k=1;k<=n+1;k++)
           if(map[tt][k]>0&&level[k]==-1)
           {
               level[k]=level[tt]+1;
               qu.push(k);
           }
   }
   if(level[n+1]!=-1)return 1;
   else return 0;
}
void dinic()
{
    SUM=0;
    mark=0;
    while(bfs())
    {
        SUM+=dfs(0,inf);
    }
    return ;
}

void print()
{
    if(SUM==0)
    {
        printf("No Solution!\n");
        return ;
    }
    int i,j;
    printf("%d\n",SUM);
    for(i=0;i<=m;i++)//这方法开始没想到,看的别人的 还是对网络流了解不深
        for(j=m+1;j<=n+1;j++)
        if(map[i][j]==0&&i!=0&&j!=n+1)
           printf("%d %d\n",i,j);
    return ;
}

int main()
{
    while(~scanf("%d%d",&m,&n))
    {
        int i,j;
        memset(map,-1,sizeof(map));
        for(i=1;i<=m;i++)
        {
             map[0][i]=1;
             map[i][0]=0;
        }

        for(i=m+1;i<=n;i++)
        {
            map[i][n+1]=1;
            map[n+1][i]=0;
        }

        while(~scanf("%d%d",&i,&j))
        {
            if(i==-1&&j==-1)break;
            map[i][j]=1;
            map[j][i]=0;
        }
        dinic();
        print();
    }
    return 0;
}

  (二)链表,加边

代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<queue>
#include<cstring>
#define Min(a,b)a<b?a:b
#define inf 1000
using namespace std;
int level[102],head[102];
int m,n,s_edge,SUM;
struct Edge
{
    int from,to,w,next;
}edge[12002];

void addedge(int u,int v, int ww )
{
    s_edge++;
    edge[s_edge].from=u;
    edge[s_edge].to=v;
    edge[s_edge].w=ww;
    edge[s_edge].next=head[u];
    head[u]=s_edge;

    s_edge++;
    edge[s_edge].from=v;
    edge[s_edge].to=u;
    edge[s_edge].w=0;
    edge[s_edge].next=head[v];
    head[v]=s_edge;

}
int dfs(int x,int Cap)
{
    if(x==n+1)return Cap;
    int y=0,t,temp,To;
    for(t=head[x];t!=-1;t=edge[t].next)
    {   To=edge[t].to;
        if(level[To]==level[x]+1&&edge[t].w>0&&Cap-y>0)
        {
            temp=Min(Cap-y,edge[t].w);
            int tt=dfs(To,temp);
            edge[t].w-=tt;
            edge[t^1].w+=tt;
            y+=tt;
        }
    }
    return y;
}

int bfs()
{
    int t,To,tt;
    queue<int>qu;
    memset(level,-1,sizeof(level));
    level[0]=0;
    qu.push(0);
    while(!qu.empty())
    {
         tt=qu.front();
        qu.pop();
        for(t=head[tt];t!=-1;t=edge[t].next)
        {
            To=edge[t].to;
            if(level[To]==-1&&edge[t].w>0)
             {
                level[To]=level[tt]+1;
                qu.push(To);
              }
        }

    }
    if(level[n+1]!=-1)return 1;
    else return 0 ;
}

void dinic()
{
    SUM=0;
    while(bfs())
    {
        SUM+=dfs(0,inf);
    }
    return ;
}

void print()
{

     if(SUM==0)
    {
        printf("No Solution!\n");
        return ;
    }
    int i,j;
    printf("%d\n",SUM);
    for(i=0;i<=s_edge;i+=2)
        if(edge[i].w==0&&edge[i].from!=0&&edge[i].to!=n+1)
           printf("%d %d\n",edge[i].from,edge[i].to);
    return ;
}

int main()
{
    while(~scanf("%d%d",&m,&n))
    {
        int i,j;
        s_edge=-1;
        memset(head,-1,sizeof(head));
        //memset(head,0,sizeof(head));错误,特别注意!!!
        for(i=1;i<=m;i++)
            addedge(0,i,1);//源点是0
        for(i=m+1;i<=n;i++)
            addedge(i,n+1,1);//n+1是汇点
        while(~scanf("%d%d",&i,&j))
        {
            if(i==-1&&j==-1)break;
            addedge(i,j,1);
        }
        dinic();
        print();

    }
    return 0;
}

  

posted @ 2012-01-29 20:44  快乐.  阅读(283)  评论(0编辑  收藏  举报