HOJ(哈工大) 2816

//题目类型:最大流+二分搜索 
//本题的关键在于线的长度一样长(使用二分搜索实现)
#include<iostream>
#include<queue>
#include<algorithm>
//#include<conio.h>
using namespace std;
#define narray 440
#define INF 1000000
int flow;            //最大流
int s,t;             //源点,汇点
int dis[narray][narray];        //距离
int dissort[narray*narray];
int c[narray];
int n,m,ncase,p;
int maxLen;

int capacity[narray][narray];    
int pre[narray];                  
int num[narray];                    
int d[narray];                       
int vn;
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;
}  
int build()                  
{
 int i,j,k;
 for(i=1;i<=n;i++)         //源点到电脑之间的流量
  capacity[s][i]=1;
 for(i=n+1;i<=n+m+1;i++)   //源点到其他点的流量
  capacity[s][i]=0;
 for(i=1;i<=n;i++)
 {
  for(j=1;j<=n;j++)     //电脑到电脑之间的流量
   capacity[i][j]=0;
  for(j=n+1;j<=n+m;j++)       //电脑和电源点之间构图(此处是关键)
   if(dis[i][j-n]<=maxLen)           //如果电脑和电源点之间的距离小于给定的距离,则建立一条边  
    capacity[i][j]=1;
   else
    capacity[i][j]=0;
  capacity[i][t]=0;            //电脑到汇点之间构图
 }
 for(i=n+1;i<=n+m;i++)
 {
  for(j=0;j<=n+m;j++)
   capacity[i][j]=0;
  capacity[i][t]=c[i-n];       //电源点到汇点构图(据电源点的容量)
 }
 flow=0;
 init(s,t);           
 flow = maxFlow(s,t);
 return flow;
}
int main()
{
    //freopen("1.txt","r",stdin);
 int i,j,k;
 unsigned long start;
 scanf("%d",&ncase);
 while(ncase--)
 {
  int discnt=0;
  scanf("%d%d%d",&n,&m,&p);
  vn = n+m+2;              //结点总数
  for(i=1;i<=n;i++)
   for(j=1;j<=m;j++)
   {
    scanf("%d",&dis[i][j]);
    dissort[discnt++]=dis[i][j];
   }
   for(i=1;i<=m;i++)
    scanf("%d",&c[i]);
   s=0;t=n+m+1;                    //定义超级源点和超级汇点
   sort(dissort,dissort+discnt);   //对所有的距离(相当于费用)进行升序排序(默认是升序),排序范围是[first, last) 
   int l=0,r=discnt-1,mid;         //下标从0开始 
   while(l+1<r)                    //二分法求解
   {
    mid=(l+r)/2; 
    maxLen=dissort[mid];
    int f=build();              //f为最大流
    if(f==n)                    //如果流量等于最大值(缩小费用)
     r=mid;                 
    else                       
     l=mid;                  //否则增大费用
   }
   if(discnt==1) printf("%d\n",dissort[0]*n*p);   //考虑只有一台电脑一个电源的情况,此时l==r,直接输出结果
   else if(l+1==r)
   {
    maxLen=dissort[l];
    int f=build();
    if(f==n)
     printf("%d\n",maxLen*n*p);
    else
    {
     maxLen=dissort[r];
     f=build();
     if(f==n)
      printf("%d\n",maxLen*n*p);
     else
      printf("-1\n");
    }
   }
 }
 //getch();
 return 0;
}

你可能感兴趣的:(OJ)