POJ-2112 Floyd+二分枚举+最大流(or 匈牙利)

       先根据题目所给的邻接矩阵跑一次Floyd..得到两两间的最短距离...这里要注意题目中所说的两点距离为0是两点间无法直接到达..so..输入时就判断重新赋值好了..但这里也要注意..由于两两间的间接距离最大可能为30*200*200=1200000..所以赋值一个>1200000才是...我就这里没注意WA了好几次...

       跑了Floyd将所有machine与cow的边提出来...排个序..然后就二分夹逼这这些..确定一个mid=(l+r)/2...做二分图匹配..这里用匈牙利和最大流都好..我用的最大流..就是只有某边的长度不大于所枚举line[mid]的长度才能使用...


Program:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
#define oo 2000000000
#define ll long long
using namespace std; 
int K,C,M,n,arc[305][305],pay[305][305],x,line[8005],MaxFlow;
int dis[305],num,way[305];
queue<int> myqueue;
bool BFS()
{
       int i,h,k;
       while (!myqueue.empty()) myqueue.pop();
       memset(dis,0,sizeof(dis));
       myqueue.push(0);
       dis[0]=1;
       while (!myqueue.empty())
       {
              h=myqueue.front();
              myqueue.pop();
              for (i=0;i<=n;i++)
                 if (!dis[i] && arc[h][i] && pay[h][i]<=x)
                 {
                         dis[i]=dis[h]+1;
                         myqueue.push(i);
                 }
       }
       return dis[n];
}
bool DFS(int h,int Flow)
{
       int i;
       way[++num]=h;
       if (h==n)
       {
             MaxFlow+=Flow;
             for (i=2;i<=num;i++)
             {
                   arc[way[i-1]][way[i]]-=Flow;
                   arc[way[i]][way[i-1]]+=Flow;
             }
             return true;
       } 
       for (i=0;i<=n;i++)
       if (dis[i]-dis[h]==1 && arc[h][i] && pay[h][i]<=x)
       { 
             if (DFS(i,min(Flow,arc[h][i]))) return true;
       } 
       num--;
       return false;
}
bool Dinic()
{
       int i,j;
       memset(arc,0,sizeof(arc));
       for (i=1;i<=K;i++) arc[0][i]=M; 
       for (i=K+1;i<=n;i++) arc[i][n]=1;
       for (i=1;i<=K;i++)
          for (j=K+1;j<n;j++) arc[i][j]=1;
       num=0;
       MaxFlow=0;
       while (BFS())
       {
             num=0;
             DFS(0,oo);
       }
       return MaxFlow==C;
}
int main()
{      
       freopen("input.txt","r",stdin);
       freopen("output.txt","w",stdout);
       int i,j,k,l,r,mid;
       scanf("%d%d%d",&K,&C,&M);
       memset(pay,0,sizeof(pay));
       for (i=1;i<=K+C;i++)
          for (j=1;j<=K+C;j++)
          {
               scanf("%d",&pay[i][j]);
               if (!pay[i][j]) pay[i][j]=2000000;
          }
       n=K+C+1;
       for (k=1;k<n;k++)
          for (i=1;i<n;i++)
             for (j=1;j<n;j++)
                if (pay[i][j]>pay[i][k]+pay[k][j])
                   pay[i][j]=pay[i][k]+pay[k][j];
       r=0;
       for (i=1;i<=K;i++)
          for (j=K+1;j<n;j++)
             line[++r]=pay[i][j];
       sort(line+1,line+1+r);
       while (line[r]>2000000) r--;
       l=0;
       while (r-l>1)
       {
              mid=(l+r)/2;
              x=line[mid];
              if (Dinic()) r=mid;
                 else l=mid;
       }
       printf("%d\n",line[r]);
       return 0;
}


你可能感兴趣的:(c,OO,ini)