POJ 2112

//题目类型:最大流+二分搜索
//本题与09年东北四省赛Power Line题目类似
//注意:最大值不要使用0x7fffffff,否则会一直wa
#include <iostream>
//#include <conio.h>
#include <queue>
using namespace std;
#define narray 240
#define karray 31
#define carray 201
const int INF = 10000000;   //不要使用0x7fffffff,否则会一直wa
int graph[narray][narray];
int dist[carray*karray];
int k,c,m;
int distnum;
int length;
int vn;
int cnt;
int capacity[narray][narray];
int src,des;

int d[narray];           //标号
int num[narray];         //num[i]表示标号为i的顶点数有多少
int pre[narray];         //记录前驱
void Floyd()
{
     int t,i,j;
     for(t=1; t<=k+c;t++)
         for(i=1;i<=k+c;i++)
              for(j=1; j<=k+c; j++)
              {
                 if(graph[i][t]<INF && graph[t][j]<INF && graph[i][j]>graph[i][t]+graph[t][j])
                     graph[i][j] = graph[i][t]+graph[t][j];
              }
                  //graph[i][j]=min(graph[i][t]+graph[t][j],graph[i][j]);

}
void init(int src,int des)             
{
     int i,j;
     queue<int> myqueue;
     myqueue.push(des);
     memset(num,0,sizeof(num));
     for(i=0;i<vn;++i)     
        d[i] = INF;
     d[des] = 0;            
     num[0] = 1;
     int frontint;
     while(!myqueue.empty()) 
     {
         frontint = myqueue.front();myqueue.pop();
         for(i=0;i<vn;++i)
         {
             if(d[i]>=vn && capacity[i][frontint]>0)  
             {
                 d[i] = d[frontint]+1;
                 myqueue.push(i); 
                 num[d[i]]++;    
             }                 
         }
     }
}
int findarc(int t)             
{
    int i,j;
    for(i=0;i<vn;++i)
    {
        if(capacity[t][i]>0 && d[t]==d[i]+1) return i;
    }
    return -1;
}
int relabel(int t)             
{
    int i,j;
    int mm = INF;
    for(i=0;i<vn;++i)
    {
        if(capacity[t][i]>0) mm = min(mm,d[i]+1);
    }
    return mm==INF?vn:mm;
}
int maxFlow(int src,int des)
{
    int sumflow = 0;
    int delta;
    int i=src;     
    int j;
    memset(pre,-1,sizeof(pre));   
    while(d[src]<vn)
    {
       j = findarc(i);
       if(j>=0)
       {
           pre[j] = i;
           i = j;          
           if(i==des)        
           {
               delta = INF;
               for (i=des;i!=src;i=pre[i]) delta=min(delta,capacity[pre[i]][i]);   
               for (i=des;i!=src;i=pre[i]) capacity[pre[i]][i] -= delta, capacity[i][pre[i]] += delta;
               sumflow += delta;
           }
       }
       else
       {
           int x = relabel(i);
           num[x]++;
           num[d[i]]--;
           if(num[d[i]]==0) return sumflow;    
           d[i] = x;
           if(i!=src) i =pre[i];          
       }
    }
    return sumflow;
}  

bool build()
{
     int i,j;
     memset(capacity,0,sizeof(capacity));
     for(i=1;i<=k;++i)
     {
         capacity[src][i]= m;
     }              
     for(i=k+1;i<=k+c;++i)
     {
         capacity[i][des] = 1;
     }      
     for(i=1;i<=k;++i)
     {
         for(j=k+1;j<=k+c;++j)
         {
             if(graph[i][j]<=length)
                capacity[i][j] =1;
             else
                capacity[i][j] =0;
         }
     }
     init(src,des);
     if(maxFlow(src,des)>=c) return true;
     else return false;     
}
int main()
{
    //freopen("1.txt","r",stdin);
    int i,j;
    while(scanf("%d%d%d",&k,&c,&m)!=-1)
    {
        vn = k+c+2;                  
        distnum = 0;
        src = 0;
        des = k+c+1;
        for(i=1;i<=k+c;++i)
        {
            for(j=1;j<=k+c;++j)
            {
                scanf("%d",&graph[i][j]);
                if(graph[i][j]==0) graph[i][j]=INF;   //输入的数据中0代表无穷大(此处注意变换)
            }
        }
        Floyd();                   //使用Floyd算法求出最短距离
        for(i=k+1;i<=k+c;++i)
        {
            for(j=1;j<=k;++j)
              dist[distnum++] = graph[i][j];
        }
        sort(dist,dist+distnum);       //对奶牛和奶牛机之间的距离排序
        int l=0,r=distnum-1,mid;
        while(l+1<r)            //枚举
        {
            mid = (l+r)/2;           
            length = dist[mid];
            if(build())  r = mid;
            else l = mid;   
        }
        if(distnum==1)       //注意考虑只有一个元素的情况
        {
            printf("%d\n",dist[0]);
        }
        else if(l+1==r)
        {
             length = dist[l];
             if(build())
             {
                 printf("%d\n",length);
             }  
             else
             {
                 length = dist[r];
                 if(build())
                    printf("%d\n",length);     
             }
        }      
        /*  也可采用这种方法进行枚举 (但是时间效率比较低,极易超时)
        int l=0,r=10000,mid;         
        while(l<r)
        {
            mid = (l+r)/2;           
            length = mid;
            if(build())  r = mid;   //此处不要写成mid+1,因为流量正好等于c 
            else l = mid+1;   
        }
        printf("%d\n",r);
        */
    }
    //getch();
    return 0;
}

 本题亦可采取二分匹配+二分搜索的方法

//二分匹配(匈牙利算法)+二分搜索
#include <iostream>
//#include <conio.h>
using namespace std;
#define narray 240
const int INF = 10000000;
int map[narray][narray];
int graph[narray][narray];
bool final[narray];
int cap[narray];
int match[narray][narray];
int k,c,m;
void Floyd()
{
     int i,j,t;
     for(t=1;t<=k+c;++t)
     {
         for(i=1;i<=k+c;++i)
         {
             for(j=1;j<=k+c;++j)
             {
                  if(map[i][t]<INF && map[t][j]<INF && map[i][j]>map[i][t]+map[t][j])
                      map[i][j] = map[i][t]+map[t][j];
             }
         }
     }
}
void build(int length)
{
     int i,j;
     memset(graph,0,sizeof(graph));
     for(i=k+1;i<=k+c;++i)
     {
         for(j=1;j<=k;++j)
         {
              if(map[i][j]<=length)
                 graph[i-k][j] = 1;
         }
     }
}
bool DFS(int p)
{
     int i,j;
     for(i=1;i<=k;++i)
     {
          if(graph[p][i] && !final[i])
          {
              final[i] = true;
              if(cap[i])                       //如果奶牛机的容量不为0
              {
                  cap[i]--;
                  match[i][++match[i][0]]=p;
                  return true;
              }
              else
              {
                  for(j=1;j<=match[i][0];++j)  //match[i][0]记录第i个奶牛机匹配的奶牛数
                  {
                      if(DFS(match[i][j]))
                      {
                           match[i][j] = p;
                           return true;
                      }
                  }
              }
          }
     }
     return false;
}
bool mat()
{
     int i,j;
     memset(match,0,sizeof(match));    //注意初始化match
     for(i=1;i<=k;++i) cap[i]=m;       //记录奶牛机的容量      
     for(i=1;i<=c;++i)                 //从奶牛进行匹配,不是从奶牛机
     {
         memset(final,0,sizeof(final));
         if(!DFS(i)) return false;
     }   
     return true;
}
int main()
{
    //freopen("1.txt","r",stdin);
    int i,j;
    while(scanf("%d%d%d",&k,&c,&m)!=-1)
    {
        for(i=1;i<=k+c;++i)
        {
            for(j=1;j<=k+c;++j)
            {
                scanf("%d",&map[i][j]);
                if(map[i][j]==0) map[i][j]=INF;              
            }              
        }                         
        Floyd();
        int l= 0,r=10000,mid;
        while(l<r)
        {
            mid = (l+r)/2;
            build(mid);
            if(mat()) r= mid;
            else l = mid+1;
        }
        printf("%d\n",r);
    }
    //getch();
    return 0;
}

posted @ 2010-06-10 15:52  北海小龙  阅读(522)  评论(0编辑  收藏  举报