【luogu4011】孤岛营救问题(拯救大兵瑞恩) (最短路)(分层思想)

P4011 孤岛营救问题

我可能是个废人 按着书上打都能搞一上午

好像是个网络流的题 还在网络流24题里 结果没一个写网络流 要不是bfs要不就是最短路

想练dijkstra 结果例二就给我来个这个东西 把书上程序spfa改成dijkstra

开始忘了运行build函数然后死活输出-1QAQ 后面又数组开小了 全!都!开!小!了!开!小!了!小!了!

一直都没想过数组小了会和输出答案有关 一直看看看看 看书看程序 然后突然开窍 我是不是数组开小了?然后.......

把每个(X,Y)的单元看作一个点 然后相互联通的单元连一条权值为1的边

然后就是连边了 把图分为2p层 就是状态压缩 每层分别为拥有钥匙的状态 然后根据状态来连边建图。 对于有钥匙的点 就将它向对应有钥匙的点连一条权值为0的边

过程比较玄幻

  1 /*
  2 id:gww
  3 language:C--
  4 Kruskal模版! 
  5 */
  6 #include<bits/stdc++.h>
  7 using namespace std;
  8 #define rg register
  9 const int N=20,inf=0x3f3f3f3f;
 10 int row,line,nk,zk,nw,num[N][N],tot=0;
 11 //列 行 钥匙数 门/墙 标号 
 12 int mp[N*N][N*N],kn[N];
 13 struct key
 14 {
 15     int x,y;
 16 }ky[N][N*N];
 17 inline int rd()
 18 {
 19     int x=0,w=0;char ch=0;
 20     while(!isdigit(ch)) w|=ch=='-',ch=getchar();
 21     while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
 22     return w?-x:x;
 23 }
 24 
 25 int head[1000000],cnt=0;
 26 struct edge
 27 {
 28     int v,nxt,w;
 29 }e[1000000];
 30 void add(int u,int v,int w)
 31 {
 32     e[++cnt].v=v;
 33     e[cnt].w=w;
 34     e[cnt].nxt=head[u];
 35     head[u]=cnt;
 36 }
 37 
 38 bool havek[N];
 39 int m,n,layer;
 40 void build()
 41 {
 42     layer=1<<zk,n=tot*layer;
 43     //每层节点数 层数 总结点数
 44     for(int s=0;s<layer;s++)
 45     {
 46         for(int i=1;i<=zk;i++)//当前状态是否有钥匙 
 47         if(s&(1<<(i-1))) havek[i]=1;
 48         else havek[i]=0;
 49         for(int i=1;i<=row;i++)
 50         for(int j=1;j<=line;j++)
 51         {
 52             int pos1=num[i][j],pos2=num[i][j+1];//向右
 53             if(pos2&&mp[pos1][pos2]+1)//有节点且非墙
 54             if(!mp[pos1][pos2]||havek[mp[pos1][pos2]])//无门||有钥匙
 55             add(pos1+tot*s,pos2+tot*s,1),add(pos2+tot*s,pos1+tot*s,1);
 56             pos2=num[i+1][j];//向下 
 57             if(pos2&&mp[pos1][pos2]+1)//有节点且非墙
 58             if(!mp[pos1][pos2]||havek[mp[pos1][pos2]])//无门||有钥匙
 59             add(pos1+tot*s,pos2+tot*s,1),add(pos2+tot*s,pos1+tot*s,1);
 60         }
 61         for(int i=1;i<=zk;i++)//转移到其他状态
 62         if(!havek[i])//么得钥匙才转移
 63         {
 64             int is=(s+(1<<(i-1)));//目标状态
 65             for(int j=1;j<=kn[i];j++)
 66             {
 67                 int pos=num[ky[i][j].x][ky[i][j].y];
 68                 add(pos+tot*s,pos+tot*is,0);
 69             }
 70         }
 71      } 
 72 }
 73 struct node
 74 {
 75     int dis,pos;
 76     node():dis(0),pos(0){}
 77     node(int a,int b):dis(a),pos(b){}
 78     bool operator <(const node &x)const
 79     {return x.dis<dis;}
 80 };
 81 int dis[N<<N];bool vis[N<<N];
 82 priority_queue<node> q;
 83 void dij(int x)
 84 {
 85     for(int i=1;i<=n;i++) dis[i]=inf,vis[i]=0;
 86     dis[x]=0;q.push(node(0,x));
 87     while(q.size())
 88     {
 89         int u=q.top().pos;q.pop();
 90         if(vis[u]) continue;
 91         vis[u]=1;
 92         for(int i=head[u];i;i=e[i].nxt)
 93         {
 94             int v=e[i].v,w=e[i].w;
 95             if(dis[v]>dis[u]+w)
 96             {
 97                 dis[v]=dis[u]+w;
 98                 q.push(node(dis[v],v));
 99             }
100         }
101     }
102 }
103 
104 int main()
105 {
106     row=rd(),line=rd(),zk=rd(),nw=rd();
107     for(rg int i=1;i<=row;i++)//初始化标号 
108     for(rg int j=1;j<=line;j++) num[i][j]=++tot;
109     for(int i=1;i<=nw;i++)
110     {
111         int x1=rd(),y1=rd(),x2=rd(),y2=rd(),g=rd();
112         int pos1=num[x1][y1],pos2=num[x2][y2];
113         if(g==0) g=-1;//为墙 
114         mp[pos1][pos2]=mp[pos2][pos1]=g;
115     }
116     nk=rd();
117     for(int i=1;i<=nk;i++)
118     {
119         int x=rd(),y=rd(),g=rd();
120         ky[g][++kn[g]].x=x,ky[g][kn[g]].y=y;
121     }
122     build();
123     dij(1);
124     int ans=inf;
125     for(int i=0;i<layer;i++)
126     ans=min(ans,dis[i*tot+tot]);
127     if(ans<inf) printf("%d",ans);
128     else printf("-1");
129     return 0;
130 }

猜你喜欢

转载自www.cnblogs.com/lxyyyy/p/10417489.html