最初的想法是二分搜索+二分匹配。
wa了之后,才知道正解应该是:最短路径+二分搜索+多重匹配。
对二分匹配的理解又加深一步。
二分搜索答案,可行性判断的时候,搜索范围应该是左开右闭区间(就是right保证可行,而left-1保证不可行。。。来源:http://hi.baidu.com/forsona/blog/item/f46ed0618b9a4dd78db10dff.html
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define maxn 250 #define maxcost 1e8 int g[maxn][maxn]; int map[maxn][maxn],maxlen; int k,c,m; bool vis[35]; int my[35][35]; void init() { int i,j; cin>>k>>c>>m; for(i=1;i<=k+c;i++) for(j=1;j<=k+c;j++) { scanf("%d",&g[i][j]); if(g[i][j]==0) g[i][j]=maxcost; } } void Floyd() { int i,j,v,sumn=k+c; for(v=1;v<=sumn;v++) for(i=1;i<=sumn;i++) for(j=1;j<=sumn;j++) if(g[i][j]>g[i][v]+g[v][j]) g[i][j]=g[i][v]+g[v][j]; } bool find(int p,int mid) { int i,j; for(i=1;i<=k;i++) { if(vis[i]&&map[p][i]&&map[p][i]<=mid) { vis[i]=false; if(my[i][0]<m)//判断容量 { my[i][++my[i][0]]=p; return true; } else { for(j=1;j<=my[i][0];j++) if(find(my[i][j],mid)) { my[i][j]=p; return true; } } } } return false; } bool match(int mid)//多重匹配 { int i; for(i=1;i<=k;i++) my[i][0]=0; for(i=1;i<=c;i++) { memset(vis,true,sizeof(vis)); if(!find(i,mid)) return false; } return true; } void solve() { int mid; int left=0,right=maxlen; while(left<right) { mid=(left+right)>>1; if(match(mid)) right=mid; else left=mid+1; } printf("%d\n",right); } void create() { int i,j; maxlen=-1; for(i=1+k;i<=c+k;i++) for(j=1;j<=k;j++) { map[i-k][j]=g[i][j]; if(map[i-k][j]>maxlen) maxlen=map[i-k][j]; } } int main() { init(); Floyd(); create(); solve(); return 0; }