求割来计算最大流,问题求补,条件是对偶问题的不对称性,形象来说,就是已知棋盘格子数,大部分都是棋子,求棋子个数,当然数空格数,就是这个道理。
#include <cstdio>
#include <queue>
#include <vector>
using namespace std;
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define INF 0x7fffffff
int abs(int a){
return a>0?a:-a;
}
int T,W,H,B,x[2004],y[2004];
int edge[2][1002][1002],edge2[1002][1002];
int dis[1002];
bool vis[1002];
int main(){
freopen("C-large-practice .in","r",stdin);
freopen("out2","w",stdout);
scanf("%d",&T);
for(int cas=1; cas<=T; ++cas){
scanf("%d%d%d",&W,&H,&B);
for(int i=0; i<2*B; i+=2){
scanf("%d%d%d%d",x+i,y+i,x+i+1,y+i+1);
}
x[2*B]=-1; y[2*B]=0; x[2*B+1]=-1; y[2*B+1]=H-1;
x[2*B+2]=x[2*B+3]=W; y[2*B+2]=0; y[2*B+3]=H-1;
for(int i=0; i<B+2; ++i){
for(int j=0; j<B+2; ++j){
if(i==j) continue;
if(x[2*i]>=x[2*j]-1&&x[2*i]<=x[2*j+1]+1) edge[0][i][j]=edge[0][j][i]=0;
else if(x[2*i+1]>=x[2*j]-1&&x[2*i+1]<=x[2*j+1]+1) edge[0][i][j]=edge[0][j][i]=0;
else{
edge[0][i][j]=edge[0][j][i]=min(abs(x[2*j+1]-x[2*i]),abs(x[2*i+1]-x[2*j]));
edge[0][i][j]--;
}
if(y[2*i]>=y[2*j]-1&&y[2*i]<=y[2*j+1]+1) edge[1][i][j]=edge[1][j][i]=0;
else if(y[2*i+1]>=y[2*j]-1&&y[2*i+1]<=y[2*j+1]+1) edge[1][i][j]=edge[1][j][i]=0;
else{
edge[1][i][j]=edge[1][j][i]=min(abs(y[2*j+1]-y[2*i]),abs(y[2*i+1]-y[2*j]));
edge[1][i][j]--;
}
edge2[i][j]=max(edge[0][i][j],edge[1][i][j]);
}
}
for(int i=0; i<B+2; ++i)
for(int j=0; j<B+2; ++j)
edge2[i][j]=min(edge2[i][j],edge2[j][i]);
for(int i=0; i<B+2; ++i) dis[i]=INF,vis[i]=false;
dis[B]=0;
priority_queue<pair<int,int> > q;
q.push(make_pair(0,B));
while(q.empty()==false){
pair<int,int> tmp=q.top();
if(tmp.second==B+1) break;
vis[tmp.second]=true;
q.pop();
for(int i=0; i<B+2; ++i){
if(vis[i]) continue;
if(-tmp.first+edge2[i][tmp.second]<dis[i]){
q.push(make_pair(tmp.first-edge2[i][tmp.second],i));
dis[i]=-tmp.first+edge2[i][tmp.second];
}
}
}
printf("Case #%d: %d\n",cas,dis[B+1]);
}
}