JZOJ 1610. 【东莞市选2008】导弹
题目:
题意:
给出每个节点到其他节点的权值,再让你构建一个二分图,要求其最大匹配最小
分析:
因为,所以我们可以直接用预处理出每个点到其他点的最短路
然后就是用二分确定我们的二分图的最大边值,在二分的函数中使用匈牙利算法求最大匹配
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<set>
#include<queue>
#include<vector>
#include<map>
#include<list>
#include<ctime>
#include<iomanip>
#include<string>
#include<bitset>
#include<deque>
#include<set>
#define LL long long
using namespace std;
inline LL read(){
LL d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
return d*f;
}
int t[105][105],m1,m2;
int c1[105],c2[105],tf[105];
struct node{
int to,next;
}e[10005];
int cnt=0,ls[205],HZB[105];
void add(int x,int y)
{
e[cnt]=(node){y,ls[x]};
ls[x]=cnt++;
return;
}
bool dfs(int k)
{
for(int i=ls[k];~i;i=e[i].next)
{
int s=e[i].to;
if(!tf[s])
{
tf[s]=1;
if(!HZB[s]||dfs(HZB[s])) {HZB[s]=k;return 1;}
}
}
return 0;
}
bool check(int x)
{
memset(ls,-1,sizeof(ls));
memset(HZB,0,sizeof(HZB));
cnt=0;
for(int i=1;i<=m1;i++)
for(int j=1;j<=m2;j++)
if(t[c1[i]][c2[j]]<=x) add(i,j);
int sum=0;
for(int i=1;i<=m1;i++)
{
memset(tf,0,sizeof(tf));
if(dfs(i)) sum++;
}
return sum==m2;
}
int main()
{
// freopen("c.in","r",stdin);
// freopen("c.out","w",stdout);
int n=read();
memset(t,0x3f3f3f3f,sizeof(t));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
t[i][j]=read();
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
t[i][j]=min(t[i][j],t[i][k]+t[k][j]);
m1=read(); for(int i=1;i<=m1;i++) c1[i]=read();
m2=read(); for(int i=1;i<=m2;i++) c2[i]=read();
int l=1,r=1000000;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid)) r=mid-1;
else l=mid+1;
}
cout<<l;
return 0;
}