[POI2009]WIE-Hexer

 

当有了另外的限制条件的时候(必须要有对应的剑),就要考虑分层图,每一层都对用了一种现在有的剑的状态,当然不是建2^13张图

而是多开一维,表示现在有的剑,到了一条路,要判断是否要求的剑都有了,可以用if((edge[i].mst|mst)!=mst) continue来判断

每次只有当弹出队首的,才更新d[u][mst]的mst,意思是只有这条路考虑清楚了,才能再往下走,

不过考试好像考了,我也写不出来的样子,好像也不是很会考的样子

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 #include<stack>
 8 #include<set>
 9 #include<map>
10 using namespace std;
11 #define mpr(x,y,z) make_pair(make_pair(x,y),z)
12 int read(){
13   int f=1,x=0;char s=getchar();
14   while(s<'0'||s>'9'){if(s=='-') f=-1;s=getchar();}
15   while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
16   return x*f;
17 }
18 const int maxn=207;
19 const int maxm=3007;
20 const int maxp=10007;
21 const int INF=0x7f7f7f7f;
22 typedef pair<int,int>pii;
23 priority_queue<pair<pii,int>,vector<pair<pii,int> >,greater<pair<pii,int> > > q;
24 int n,m,p,k,num;
25 int s[maxn],head[maxn],d[maxn][maxp];
26 bool vis[maxn][maxp];
27 struct Edge{
28   int nxt,to,dis,mst;
29 }edge[maxm<<1];
30 void add(int from,int to,int dis,int mst){
31   edge[++num].nxt=head[from];
32   edge[num].to=to;
33   edge[num].dis=dis;
34   edge[num].mst=mst;
35   head[from]=num;
36 }
37 int Dij(){
38   memset(d,INF,sizeof(d));
39   memset(vis,false,sizeof(vis));
40   d[1][0]=0;q.push(mpr(0,1,0));
41   while(!q.empty()){
42     int w=q.top().first.first;
43     int u=q.top().first.second;
44     int mst=q.top().second;
45     q.pop();
46     if(u==n) return w;
47     if(vis[u][mst]) continue;
48     vis[u][mst]=true;mst|=s[u];
49     for(int i=head[u];i;i=edge[i].nxt){
50       int v=edge[i].to;
51       if((edge[i].mst|mst)!=mst) continue;
52       if(d[v][mst]>w+edge[i].dis){
53         d[v][mst]=w+edge[i].dis;
54         q.push(mpr(d[v][mst],v,mst));
55       }
56     }
57   }
58   return -1;
59 }
60 int main(){
61   n=read();m=read();p=read();k=read();
62   for(int i=1;i<=k;i++){
63     int u,v,w;u=read();v=read();
64     for(int j=1;j<=v;j++){
65       w=read();s[u]|=(1<<(w-1));
66     }
67   }
68   for(int i=1;i<=m;i++){
69     int x,y,t,s,w;
70     x=read();y=read();t=read();s=read();
71     int tmp=0;
72     for(int i=1;i<=s;i++){
73       w=read();
74       tmp|=(1<<(w-1));
75     }
76     add(x,y,t,tmp);add(y,x,t,tmp);
77   }
78   cout<<Dij()<<endl;
79   return 0;
80 }

 

转载于:https://www.cnblogs.com/lcan/p/9909151.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值