求割来计算最大流,问题求补,条件是对偶问题的不对称性,形象来说,就是已知棋盘格子数,大部分都是棋子,求棋子个数,当然数空格数,就是这个道理。
#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]); } }