POJ 3057 <二分图匹配>

来源:互联网 发布:nba2012东部决赛数据 编辑:程序博客网 时间:2024/06/14 14:38

题意是给一个矩阵。

这个矩阵由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;elsereturn 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;elsereturn 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;}