链接:http://poj.org/problem?id=3057
题意:一个二维平面图,有“D”门,“X”墙,“.”人,每个门每秒只能走一个人,人可以重叠,问最短几秒人可以走光。
思路:开始胡乱YY的,就没写,后来看的题解= =(弱逼不会建图啊啊啊啊啊)。二分图最大匹配要求一个点只能连一条边,这个题的门显然不符合。不过可以把门拆成第x秒的门,这样就符合了,二分答案,建图。
具体做法:
1.把相邻的能走的点之间的距离设为1
2.floyd求出任意两点之间距离
3.把人和门分别存到两个vector里,vector里面存的是在数组中的位置
4.二分答案
5.建图:枚举人和门,如果距离小于当前二分的答案,就建边(可能不止建一条边,我可以停顿1s在过去||在门口排队。。)
代码://115行之后开始=。=
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
#define mem(a,b) memset((a),(b),sizeof((a)))
#define For(i,a,b) for(int (i)=(a);(i) < (b);(i)++)
#define Ror(i,a,b) for(int (i)=(a);(i) > (b);(i)--)
#define mp make_pair
#define pb push_back
#define inf 0x3f3f3f3f
void RI (int& x){
x = 0;
char c = getchar ();
while (c == ' '||c == '\n') c = getchar ();
bool flag = 1;
if (c == '-'){
flag = 0;
c = getchar ();
}
while (c >= '0' && c <= '9'){
x = x * 10 + c - '0';
c = getchar ();
}
if (!flag) x = -x;
}
void RII (int& x, int& y){RI (x), RI (y);}
void RIII (int& x, int& y, int& z){RI (x), RI (y), RI (z);}
const int maxn = 30000;
const int maxm = 40001000;
vector<int> g[maxn];
int Mx[maxn],My[maxn],Nx,Ny;
int dx[maxn],dy[maxn],dis;
bool vst[maxn];
bool searchP()
{
queue<int>Q;
dis=inf;
memset(dx,-1,sizeof(dx));
memset(dy,-1,sizeof(dy));
for(int i=0;i<Nx;i++)
if(Mx[i]==-1)
{
Q.push(i);
dx[i]=0;
}
while(!Q.empty())
{
int u=Q.front();
Q.pop();
if(dx[u]>dis) break;
int siz = g[u].size();
For(i,0,siz){//cout<<siz;
int v = g[u][i];
if(dy[v]==-1)
{
dy[v]=dx[u]+1;
if(My[v]==-1) dis=dy[v];
else
{
dx[My[v]]=dy[v]+1;
Q.push(My[v]);
}
}
}//
}
return dis!=inf;
}
bool DFS(int u)
{
int siz = g[u].size();
For(i,0,siz){
int v = g[u][i];
if(!vst[v]&&dy[v]==dx[u]+1)
{
vst[v]=1;
if(My[v]!=-1&&dy[v]==dis) continue;
if(My[v]==-1||DFS(My[v]))
{
My[v]=u;
Mx[u]=v;
return 1;
}
}
}
return 0;
}
int MaxMatch()
{
int res=0;
memset(Mx,-1,sizeof(Mx));
memset(My,-1,sizeof(My));
while(searchP())
{
memset(vst,0,sizeof(vst));
for(int i=0;i<Nx;i++)
if(Mx[i]==-1&&DFS(i)) res++;
}
//For(i,0,Nx)if(Mx[i] == -1)cout<<i<<endl;
return res;
}
//**************************************************************************/
char mm[400][400];
int ddd[400][400];
int ddx[4] = {0,0,1,-1};
int ddy[4] = {1,-1,0,0};
int cc[400] = {1,-1,};
vector<int>door,peo;
void build(int mid){
Nx = door.size()*mid;
Ny = peo.size();
For(i,0,Nx)g[i].clear();
For(i,0,Nx/mid){
For(j,0,Ny){
For(k,ddd[door[i]][peo[j]],mid+1){
g[i*mid+k-1].pb(j);
}
}
}
}
int get(int r){
int l = 1,mid;
while(l < r){
mid = (l + r) >> 1;
build(mid);
int ans = MaxMatch();//if(mid == 3)cout<<ans<<endl;
if(ans < peo.size())l = mid + 1;
else r = mid;
}
return r;
}
bool vis[400];
bool judge(){
mem(vis,0);
int siz = door.size();
int peo_num = peo.size();//cout<<siz<<' '<<peo_num;
For(i,0,siz){
int now = door[i];
For(j,0,peo_num){
if(ddd[now][peo[j]] != inf)vis[peo[j]] = 1;
}
}
For(i,0,peo_num){
if(vis[peo[i]] == 0)return false;
}
return true;
}
int main(){
//freopen("test.txt","r",stdin);
int T;
RI(T);
while(T --){
int n,m;
RII(n,m);
For(i,0,n){
scanf("%s",mm[i]);
}
mem(ddd,inf);
door.clear();
peo.clear();
cc[2] = m;cc[3] = -m;
For(i,0,n*m){
int x = i/m,y = i%m;
if(mm[x][y] == 'X')continue;
if(mm[x][y] == 'D')door.pb(i);
else peo.pb(i);
For(j,0,4){
int tx = x + ddx[j],ty = y + ddy[j];
if(tx >= 0&&ty >= 0&&tx < n&&ty < m&&
((mm[x][y] == '.'&&mm[tx][ty] == '.')||
(mm[x][y] == '.'&&mm[tx][ty] == 'D')||
(mm[x][y] == 'D'&&mm[tx][ty] == '.')))
{
ddd[i][i+cc[j]] = 1;//cout<<x<<' '<<y<<' '<<tx<<' '<<ty<<endl;
}
}
}
For(i,0,n*m)ddd[i][i] = 0;
For(k,0,n*m){
For(i,0,n*m){
For(j,0,n*m){
ddd[i][j] = min(ddd[i][j],ddd[i][k] + ddd[k][j]);
}
}
}
if(judge() == false){
puts("impossible");
continue;
}
else {//cout<<peo.size();
int ans = get(n*m);
if(peo.size() == 0)ans = 0;
cout<<ans<<endl;
}
}
}