洛谷P4011 【网络流24题】 孤岛营救问题 (BFS+状压)
一道妙题啊......(不知道为什么这道题的标签是网络流,不需要用网络流啊)
如果没有门和钥匙,连边(边权为1)求最短路就行了。
但是有这两个因素的限制,我们采用分层建图的思想,一共2p层,每层对应持有钥匙的2p种状态(就是状态压缩),在分层图上连边,当前层没有的钥匙,就向有该类钥匙的层连边(注意此时的边权是0)。最后宽搜求最短路就行了,答案是每层图终点取最小值。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1e6; 4 int first[N],to[N],w[N],nxt[N],tot; 5 struct node{ 6 int x,y; 7 }key[15][20];//存钥匙 8 int n,M,row,line,keyn; 9 int layer,r,num[20][20]; 10 int fg[200][200],kn[15],dis[102500]; 11 int q[N],inf=0x3f3f3f3f; 12 bool vis[102500]; 13 14 void add(int x,int y,int z){ 15 nxt[++tot]=first[x];first[x]=tot; 16 to[tot]=y;w[tot]=z; 17 } 18 19 void build(){ 20 int i,j,k,x,y,t; 21 bool havekey[15]={0}; 22 M=row*line;//每层节点数 23 layer=1<<keyn;//总层数 24 n=layer*M;//总结点数 25 for(k=0;k<layer;k++){//对每层处理 26 for(i=1;i<=keyn;i++) 27 if(k&(1<<(i-1))) havekey[i]=true; 28 else havekey[i]=false;//该层有哪几类钥匙 29 for(i=1;i<=row;i++) 30 for(j=1;j<=line;j++){ 31 x=num[i][j];y=num[i][j+1];//向右连边 32 if(y!=0&&fg[x][y]!=-1) 33 if(fg[x][y]==0||havekey[fg[x][y]]){ 34 add(k*M+x,k*M+y,1); 35 add(k*M+y,k*M+x,1); 36 } 37 y=num[i+1][j];//向左连边 38 if(y!=0&&fg[x][y]!=-1) 39 if(fg[x][y]==0||havekey[fg[x][y]]){ 40 add(k*M+x,k*M+y,1); 41 add(k*M+y,k*M+x,1); 42 } 43 } 44 for(i=1;i<=keyn;i++)//当前层没有钥匙,转移到有该类钥匙的层 45 if(!havekey[i]){ 46 t=k+(1<<(i-1));//t表示有第i类钥匙的层 47 for(j=1;j<=kn[i];j++){ 48 x=num[key[i][j].x][key[i][j].y]; 49 add(k*M+x,t*M+x,0);//注意连边的权值是0 50 } 51 } 52 } 53 } 54 55 void Read(){ 56 int i,j,k,x,y,p; 57 cin>>row>>line>>keyn>>r;k=0; 58 for(i=1;i<=row;i++) 59 for(j=1;j<=line;j++) num[i][j]=++k;//编号 60 for(i=1;i<=r;i++){ 61 scanf("%d%d",&x,&y);j=num[x][y]; 62 scanf("%d%d",&x,&y);k=num[x][y]; 63 cin>>p;if(p==0) p=-1;//表示墙 64 fg[j][k]=fg[k][j]=p;//有门/墙 65 } 66 cin>>r; 67 for(i=1;i<=r;i++){ 68 scanf("%d%d%d",&x,&y,&p); 69 kn[p]++; 70 key[p][kn[p]].x=x; 71 key[p][kn[p]].y=y;//第p类钥匙的第kn[p]把的位置 72 } 73 } 74 75 void SPFA(){ 76 int i,j,k,head,tail; 77 for(i=1;i<=n;i++) dis[i]=inf; 78 dis[1]=0,vis[1]=true,q[1]=1; 79 head=tail=1; 80 while(head<=tail){ 81 i=q[head]; 82 for(k=first[i];k;k=nxt[k]){ 83 j=to[k]; 84 if(dis[j]>dis[i]+w[k]){ 85 dis[j]=dis[i]+w[k]; 86 if(!vis[j]){ 87 q[++tail]=j;vis[j]=true; 88 } 89 } 90 } 91 vis[i]=false,head++; 92 } 93 } 94 95 void solve(){ 96 int i,ans=inf,T; 97 SPFA(); 98 T=num[row][line]; 99 for(i=0;i<layer;i++) 100 ans=min(ans,dis[i*M+T]); 101 if(ans==inf) cout<<-1<<endl; 102 else cout<<ans<<endl; 103 } 104 105 int main(){ 106 Read();//读入数据 107 build();//建图 108 solve(); 109 return 0; 110 }
重点还是在于建图。。。