题目链接:传送门
题意:n个城市,m条道路,要求1--N的最小花费。规定从a城市到城市的花费有两种:如果之前到过c,花费为p,否则花费为r。注意:道路是双向的。
难点:可能a到b有多条路而且花费不同这样的话邻接矩阵会错;有人可能深搜的时候会让每个城市只走一次(DFS惯性思维),但这道题不一样,因为到达下一个城市之前可能需要先到另外一个城市以降低花费。这样的话可以标记每个城市访问过的次数,可以设定让它不超过10次,网上说是3次其实这都无所谓,因为可以加一个最优化剪枝那样就算设为20次也能过(设为20的时候我跑过219ms,10次是0ms)最优化剪枝就是如果当前答案大于已经搜到最优答案,剪掉。
注意有可能无解。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cctype>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define maxn 360
#define _ll __int64
#define ll long long
#define INF 0x3f3f3f3f
#define Mod 1000000007
#define pp pair<int,int>
#define ull unsigned long long
#define max(x,y) ( ((x) > (y)) ? (x) : (y) )
#define min(x,y) ( ((x) > (y)) ? (y) : (x) )
using namespace std;
struct node
{
int u,c,wa,wb;
node (int a,int b,int x,int y)
{
u=a;c=b;wa=x;wb=y;
}
};
vector <node> eg[12];
int ok,ma[12][12][2],n,m,vis[12],ans;
void init()
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
eg[i].clear();
}
void dfs(int u,int s)
{
if(s>ans)return ;
if(u==n)
{
ok=1;ans=min(ans,s);
return ;
}
for(int i=0;i<eg[u].size();i++)
{
int v=eg[u][i].u;
if(vis[v]<=20)
{
vis[v]++;
if(vis[eg[u][i].c])
dfs(v,s+eg[u][i].wa);
else
dfs(v,s+eg[u][i].wb);
vis[v]--;
}
}
}
int main()
{
int u,v,c,wa,wb;
while(~scanf("%d%d",&n,&m))
{
init();
while(m--)
{
scanf("%d%d%d%d%d",&u,&v,&c,&wa,&wb);
eg[u].push_back(node(v,c,wa,wb));
}
ans=INF;ok=0;dfs(1,0);
if(ok)
printf("%d\n",ans);
else
puts("impossible");
}
return 0;
}