原题:
题意:
有n个草地和m个集合,每个集合内有若干个草地,表示这些草地可以任意互通,一个草地可以出现在多个集合中,问你从草地1到草地n最少需要经过多少个草地
每个集合开一个爸爸节点,集合内的点上车花1块钱,下车不花钱,然后堆优化的dij即可
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 using namespace std; 6 #define LL long long 7 const LL oo=1LL*1000000000*1000000000; 8 struct edg{int y,v,nxt;}e[2100000]; int lk[2100000],ltp=0; 9 void ist(int x,int y,int z){ 10 edg tmp; 11 tmp.y=y,tmp.v=z,tmp.nxt=lk[x]; 12 e[++ltp]=tmp; lk[x]=ltp; 13 //e[++ltp]=(edg){y,z,lk[x]}; lk[x]=ltp; 14 } 15 struct nds{ 16 int x; LL y; 17 bool operator<(nds z){ return y<z.y;} 18 bool operator>(nds z){ return y>z.y;} 19 }; 20 nds hp[2100000]; int sz=0; 21 void psh(nds z){ 22 hp[++sz]=z; 23 for(int i=sz;i>1 && hp[i]<hp[i>>1];i>>=1) swap(hp[i],hp[i>>1]); 24 } 25 void pp(){ 26 hp[1]=hp[sz--]; 27 int x=1,mn=1; 28 for(;;){ 29 mn=x; 30 if((x<<1)<=sz && hp[x<<1]<hp[mn]) mn=(x<<1); 31 if((x<<1|1)<=sz && hp[x<<1|1]<hp[mn]) mn=(x<<1|1); 32 if(mn==x) break; 33 swap(hp[mn],hp[x]); 34 x=mn; 35 } 36 } 37 int n,m; 38 LL dstc[2100000]; 39 LL a[2100000],b[2100000]; 40 void dij(int x){ 41 sz=0; 42 for(int i=1;i<=m+n;++i) dstc[i]=oo; 43 dstc[x]=0; 44 nds tmp; 45 tmp.x=x,tmp.y=0; 46 psh(tmp); 47 //psh((nds){x,0}); 48 while(sz){ 49 while(sz && hp[1].y>dstc[hp[1].x]){ 50 pp(); 51 } 52 if(!sz) break; 53 x=hp[1].x; dstc[x]=hp[1].y; 54 pp(); 55 for(int i=lk[x];i;i=e[i].nxt)if(dstc[x]+e[i].v<dstc[e[i].y]){ 56 dstc[e[i].y]=dstc[x]+e[i].v; 57 nds tmp; 58 tmp.x=e[i].y,tmp.y=dstc[e[i].y]; 59 psh(tmp); 60 //psh((nds){e[i].y,dstc[e[i].y]}); 61 } 62 } 63 } 64 void prvs(){ 65 ltp=0; 66 for(int i=1;i<=m+n;++i) lk[i]=0; 67 sz=0; 68 } 69 int main(){ 70 int T; cin>>T; 71 for(int t=1;t<=T;++t){ 72 cin>>n>>m; 73 prvs(); 74 int x,y,z; 75 for(int i=1;i<=m;++i){ 76 scanf("%d%d",&z,&y); 77 for(int j=1;j<=y;++j){ 78 scanf("%d",&x); 79 ist(x,n+i,z); 80 ist(n+i,x,0); 81 } 82 } 83 dij(1); 84 for(int i=1;i<=m+n;++i) a[i]=dstc[i]; 85 dij(n); 86 for(int i=1;i<=m+n;++i) b[i]=dstc[i]; 87 LL mn=oo; 88 for(int i=1;i<=n;++i) mn=min(mn,max(a[i],b[i])); 89 int cnt=0; 90 for(int i=1;i<=n;++i)if(max(a[i],b[i])==mn) ++cnt; 91 /* 92 cout<<"=============="<<endl; 93 for(int i=1;i<=n;++i) cout<<a[i]<<" "; 94 cout<<endl; 95 for(int i=1;i<=n;++i) cout<<b[i]<<" "; 96 cout<<endl; 97 cout<<"=============="<<endl; 98 */ 99 printf("Case #%d: ",t); 100 if(mn==oo){ 101 printf("Evil John "); 102 } 103 else{ 104 printf("%lld ",mn); 105 int sb=0; 106 for(int i=1;i<=n;++i)if(max(a[i],b[i])==mn){ 107 ++sb; 108 printf("%d",i); 109 if(sb!=cnt) printf(" "); 110 } 111 printf(" "); 112 } 113 } 114 return 0; 115 }