一个带权有向图,所有边<u,v>要么在v点收费,要么之前在某点交过费,求最小费用。
状压完图是带环的,求最短路即可。
#include <iostream>
#include <cstring>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <cstdio>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#define N 16
typedef long long LL;
#define fi first
#define se second
using namespace std;
struct edge
{
int x , c , w1 , w2;
};
vector<edge> e[N];
int n , m , d[10][1 << 10];
bool f[10][1 << 10];
void work()
{
int i , j , k , l , x; edge p;
scanf("%d%d",&n,&m);
while (m --)
{
scanf("%d%d%d%d%d",&j , &p.x , &p.c , &p.w1 , &p.w2);
-- j , -- p.x , -- p.c;
e[j].push_back(p);
}
for (i = 0 ; i < n ; ++ i)
for (j = 0 ; j < 1 << n ; ++ j)
d[i][j] = 1 << 30;
memset(f , 0 , sizeof(f));
queue< pair<int , int> > q;
f[0][1] = 1 , q.push(make_pair(0 , 1)) ,d[0][1] = 0;
while (!q.empty())
{
i = q.front().second , j = q.front().first , q.pop() , f[j][i] = 0;
for (k = 0 ; k < e[j].size() ; ++ k)
{
x = e[j][k].x;
if ((i & (1 << e[j][k].c)) && d[x][i | (1 << x)] > d[j][i] + e[j][k].w1)
{
d[x][i | (1 << x)] = d[j][i] + e[j][k].w1;
if (!f[x][i | (1 << x)])
{
f[x][i | (1 << x)] = 1;
q.push(make_pair(x , i | (1 << x)));
}
}
if (d[x][i | (1 << x)] > d[j][i] + e[j][k].w2)
{
d[x][i | (1 << x)] = d[j][i] + e[j][k].w2;
if (!f[x][i | (1 << x)])
{
f[x][i | (1 << x)] = 1;
q.push(make_pair(x , i | (1 << x)));
}
}
}
}
int ans = 1 << 30;
for (i = 0 ; i < 1 << n ; ++ i)
ans = min(ans , d[n - 1][i]);
if (ans == 1 << 30)
puts("impossible");
else cout << ans << endl;
}
int main()
{
work();
return 0;
}