您的位置:首页 > 其它

POJ 3057 <二分图匹配>

2017-06-03 14:31 357 查看
题意是给一个矩阵。

这个矩阵由X和.和D组成。

D表示门,X表示障碍物,每个.上有个人,问全部人最短逃出门的时间,每秒门只能跑一个人。

如果有人不能逃出输出impossible。

从每个人战的位置开始bfs,得到每个门到每个人的距离,如果有一个人到不了任意一个门,那么就说明有人无法逃出。

可以二分这个t,看是否所有人都能逃出。如何看呢,可以建立很多个二元组门和t,意思是比如1、2、3结点代表3个门在1s的时间,

4、5、6代表3个门在2s的时间,然后进行最大匹配(DFS搜索pre不为-1的时候,找pre[u]而不是u),如果全部人都能匹配成功,说明这个时间是可以让所有人跑掉的。

对于这些门的结点如何表示,可以新建立一个vector表明人可以连到的门,对于这个t,只有到门的时间>=t,对于这个门,这个人连接的是从到门的时间到t时间这个区间的结点,

如果这个门本身最近就要8s,而t=4s,显然就不相连

二分的时候门这么写。

for(int i=1;i<=t1;i++){
for(int j=0;j<q2[i].size();j++){
for(int k=q2[i][j].cost;k<=t;k++){
u.num=q2[i][j].num+t2*(k-1);
u.cost=k;
q3[i].push_back(u);
// cout << i <<" " <<j<< " " <<k<< endl;
}
}
}如果对于每个t每次都清空这个vecotr重新创建显然很浪费时间。
根据最大匹配的性质,其为找增广路径,那么我们可以每次t+1的时候,把所有结点能新到的门连上,保留之前的增广路径,在此基础上再向下找,这样显然省许多时间

2种方法的代码

#include <iostream>
#include <stdio.h>
#include <queue>
#include <string.h>
#include <stdlib.h>
using namespace std;
vector<int>p[150];
struct ttt{
int r,c,s;
};
struct tt2{
int num,cost;
};
int t1;
vector<tt2>q2[150];
vector<ttt>qq[150];
vector<tt2>q3[150];
char map1[40][40];
int walked[40][40];
int map2[40][40];
int dr[4]={0,1,0,-1};
int dc[4]={1,0,-1,0};
int bfs(int r,int c,int t1){
ttt u;
u.r=r;u.c=c;u.s=0;
memset(walked,0,sizeof(walked));
queue<ttt>q1;
q1.push(u);
while(!q1.empty()){
ttt v=q1.front();q1.pop();
if(map1[v.r][v.c]=='D'){
tt2 u1;
u1.num=map2[v.r][v.c];
u1.cost=v.s;
q2[t1].push_back(u1); //q2存每个空地连接的图和cost
continue;
}
u.s=++v.s;
for(int i=0;i<4;i++){
u.r=v.r+dr[i];
u.c=v.c+dc[i];
if(map1[u.r][u.c]!='X'&&walked[u.r][u.c]==0){
walked[u.r][u.c]=1;
q1.push(u);
}
}
}
if(q2[t1].size()==0)
return 0;
else
return 1;
}
int walk[150];
int pre[150];
int dfs(int x){
if(walk[x]==0){
walk[x]=1;
for(int i=0;i<q3[x].size();i++){
int u=q3[x][i].num;
if(pre[u]==-1||dfs(u)){
pre[u]=x;
return 1;
}
}
}
return 0;
}
int t2;
int fen(int t){
memset(q3,0,sizeof(q3));
tt2 u;
for(int i=1;i<=t1;i++){
for(int j=0;j<q2[i].size();j++){
for(int k=q2[i][j].cost;k<=t;k++){
u.num=q2[i][j].num+t2*(k-1);
u.cost=k;
q3[i].push_back(u);
// cout << i <<" " <<j<< " " <<k<< endl;
}
}
}
int t2=0;
memset(pre,-1,sizeof(pre));
for(int i=1;i<=t1;i++){
memset(walk,0,sizeof(walk));
if(dfs(i))t2++;
}
if(t2==t1)return 1;
else return 0;
}
int main(){
freopen("in.txt","r",stdin);
int t3,f1,f2,f3,i,j,k,l,n,m;
int k1,k2;
int g1,g2;
int r,c;
memset(map1,0,sizeof(map1));
cin >> r>> c;
t1=0;
t2=0;
for(i=1;i<=r;i++)
for(j=1;j<=c;j++){
cin >> map1[i][j];
if(map1[i][j]=='\0'||map1[i][j]=='\n'){
j--;continue;
}else if(map1[i][j]=='D'){
ttt u;
u.r=i;
u.c=j;
qq[t2].push_back(u);
//cout <<t2 << "门的" <<i << " " << j<<endl;
map2[i][j]=++t2; //map2存图的下标,从0开始
}
}
int ccc=0;
for(i=2;i<r;i++) //每个空区域都站着一个人
for(j=2;j<c;j++){
if(map1[i][j]=='.')
if(bfs(i,j,++t1)==0) //t1从1开始
ccc=1;
}
if(ccc){
cout << "impossible" << endl;return 0;
}
int left1,right1,mid1;
left1=0;right1=(r-2)*(c-2)+1;
t3=1e9+7;
while(right1>=left1){
mid1=(right1+left1)/2;
if(fen(mid1)){
right1=mid1-1;
t3=min(t3,mid1);
}else{
left1=mid1+1;
}
}
cout << t3<< endl;
return 0;
}


t一点点增加
#include <iostream>
#include <stdio.h>
#include <queue>
#include <string.h>
#include <stdlib.h>
using namespace std;
char map1[15][15];
int map2[15][15];
bool walked[15][15];
int pre[120];
int walk[120];
struct ttt{
int r,c,s;
};
int dr[4]={0,-1,0,1};
int dc[4]={1,0,-1,0};
struct tt2{
int num,cost;
};
vector<tt2>qq[120];
vector<int>qq1[120];
int cc1;
int bfs(int r,int c){
ttt u,v;
u.r=r;u.c=c;u.s=0;
queue<ttt>q1;
q1.push(u);
cc1++;
// cout << r<< " " <<c <<endl;
memset(walked,0,sizeof(walked));
while(!q1.empty()){
v=q1.front();q1.pop(); //这个点到各个门的费用
if(map1[v.r][v.c]=='D'){
tt2 u1;
u1.cost=v.s;u1.num=map2[v.r][v.c];
qq[cc1].push_back(u1);
continue;
}
u.s=++v.s;
for(int i=0;i<4;i++){
u.r=v.r+dr[i];
u.c=v.c+dc[i];
if(map1[u.r][u.c]!='X'&&walked[u.r][u.c]==0){
walked[u.r][u.c]=1;
q1.push(u);
}
}
}
if(qq[cc1].size()==0)
return 0;
else
return 1;
}
int vis[120];
int dfs(int x){
if(walk[x]==0){
walk[x]=1;
for(int i=0;i<qq1[x].size();i++){
int u=qq1[x][i];
if(pre[u]==-1||dfs(pre[u])){
pre[u]=x;
vis[x]=1; //说明x已经连有了
// cout << x << "有了" << endl;
return 1;
}
}
}
return 0;
}
int main(){
int i,j,k,f1,f2,f3,f4,t1,t2,t3,t4,r,c;
freopen("in.txt","r",stdin);
cin >> r>> c;
f1=0;
for(i=1;i<=r;i++)
for(j=1;j<=c;j++){
cin >> map1[i][j];
if(map1[i][j]=='\0'||map1[i][j]=='\n'){
j--;continue;
}else if(map1[i][j]=='D'){
map2[i][j]=++f1;
}
}
int ccc=0;
for(i=2;i<r;i++)
for(j=2;j<c;j++){
if(map1[i][j]=='.'){
if(bfs(i,j)==0)
ccc=1;
}
}
if(ccc==1){
cout << "impossible" << endl;return 0;
}
t1=0;
int res=0;
memset(pre,-1,sizeof(pre));
memset(vis,0,sizeof(vis));
while(t1<r*c){
t1++;
for(i=1;i<=cc1;i++){
for(j=0;j<qq[i].size();j++){
if(qq[i][j].cost<=t1){
qq1[i].push_back(f1*(t1-1)+qq[i][j].num);
}
}
}
for(i=1;i<=cc1;i++){
memset(walk,0,sizeof(walk));
if(vis[i]==0){
if(dfs(i)==1){
res++;}
}
}
// cout << t1 << " " <<res<< " " << cc1<<endl;
if(res>=cc1)break;
}
cout << t1<< endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: