题目大概是给一张有向图,有n张票,每张票只能使用一次,使用一张票就能用pi匹马拉着走过图上的一条边,走过去花的时间是边权/pi,问从a点走到b点的最少时间是多少。
用dp[u][S]表示当前在u点且用过的票集合是S的最少时间,丢进SPFA更新。
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 using namespace std; 5 #define INF 1e8 6 #define MAXN 33 7 #define MAXM 33*33 8 struct Edge{ 9 int u,v,next; 10 double w; 11 }edge[MAXM]; 12 int NE,head[MAXN]; 13 void addEdge(int u,int v,double w){ 14 edge[NE].u=u; edge[NE].v=v; edge[NE].w=w; 15 edge[NE].next=head[u]; head[u]=NE++; 16 } 17 struct Node{ 18 int u,S; 19 Node(int _u,int _S):u(_u),S(_S){} 20 }; 21 int n,m,t[8]; 22 double d[31][1<<8]; 23 bool vis[31][1<<8]; 24 void SPFA(int vs){ 25 memset(vis,0,sizeof(vis)); 26 vis[vs][0]=1; 27 for(int i=1; i<=m; ++i){ 28 for(int j=0; j<(1<<n); ++j) d[i][j]=INF; 29 } 30 d[vs][0]=0; 31 queue<Node> que; 32 que.push(Node(vs,0)); 33 while(!que.empty()){ 34 Node nd=que.front(); que.pop(); 35 int u=nd.u,S=nd.S; 36 for(int i=head[u]; i!=-1; i=edge[i].next){ 37 int v=edge[i].v; 38 for(int j=0; j<n; ++j){ 39 if((S>>j)&1) continue; 40 if(d[v][S^(1<<j)]>d[u][S]+edge[i].w/t[j]){ 41 d[v][S^(1<<j)]=d[u][S]+edge[i].w/t[j]; 42 if(!vis[v][S^(1<<j)]){ 43 vis[v][S^(1<<j)]=1; 44 que.push(Node(v,S^(1<<j))); 45 } 46 } 47 } 48 } 49 vis[u][S]=0; 50 } 51 } 52 int main(){ 53 int p,vs,vt,a,b; 54 double c; 55 while(~scanf("%d%d%d%d%d",&n,&m,&p,&vs,&vt) && (n||m||p||vs||vt)){ 56 NE=0; 57 memset(head,-1,sizeof(head)); 58 for(int i=0; i<n; ++i) scanf("%d",t+i); 59 while(p--){ 60 scanf("%d%d%lf",&a,&b,&c); 61 addEdge(a,b,c); addEdge(b,a,c); 62 } 63 SPFA(vs); 64 double res=INF; 65 for(int i=0; i<(1<<n); ++i){ 66 res=min(res,d[vt][i]); 67 } 68 if(res==INF) puts("Impossible"); 69 else printf("%f ",res); 70 } 71 return 0; 72 }