用mark[i][st]记录到达i点时到所有点情况为st时的最小花费,向下一步走的时候可以查看要到的点需要经过的中间点是否在st中,然后用优先队列+最短路便可以解决了。
#include<cstdio> #include<cstring> #include<queue> using namespace std; const int N=12; int head[N],nc; struct edge { int to,by,c1,c2,nxt; }edge[N*3]; void add(int a,int b,int c,int c1,int c2) { edge[nc].to=b;edge[nc].nxt=head[a];edge[nc].by=c;edge[nc].c1=c1;edge[nc].c2=c2;head[a]=nc++; } struct data { int id,cost,state; bool operator<(const data &next)const { return cost>next.cost; } data(){} data(int _id,int _cost,int _state){id=_id;cost=_cost;state=_state;} }; int mark[N][1<<N]; priority_queue<data> Q; int dfs(int n) { while(!Q.empty()) Q.pop(); memset(mark,-1,sizeof(mark)); Q.push(data(1,0,1)); int ans=-1; mark[1][1]=0; while(!Q.empty()) { data a=Q.top(); Q.pop(); if(a.id==n) { if(ans==-1||ans>a.cost) ans=a.cost; continue; } for(int i=head[a.id];i!=-1;i=edge[i].nxt) { int t=edge[i].to; int st=a.state|(1<<(t-1)); if((1<<(edge[i].by-1))&a.state) { if(mark[t][st]==-1||mark[t][st]>a.cost+edge[i].c1) { mark[t][st]=a.cost+edge[i].c1; Q.push(data(t,mark[t][st],st)); } } if(mark[t][st]==-1||mark[t][st]>a.cost+edge[i].c2) { mark[t][st]=a.cost+edge[i].c2; Q.push(data(t,mark[t][st],st)); } } } return ans; } int main() { int n,m; while(scanf("%d%d",&n,&m)!=EOF) { memset(head,-1,sizeof(head)); nc=0; for(int i=0;i<m;i++) { int a,b,c,c1,c2; scanf("%d%d%d%d%d",&a,&b,&c,&c1,&c2); add(a,b,c,c1,c2); } m=dfs(n); if(m==-1) printf("impossible\n"); else printf("%d\n",m); } return 0; }