用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;
}