版权声明:转载标注来源喔~ https://blog.csdn.net/iroy33/article/details/89944404
题意:m条路连接n个城市,道路收费,可以在ci城市付Pi钱通过ai到bi的路,或者在bi付Ri的钱,问从1到n最少需要花多少钱?
思考:如果没有在ci城市付Pi钱这一条件的话,可以以Ri为权值跑dijkstra。加上这一条件后,如果ci城市已经到达过了,就加上Pi,否则加上Ri
emm,这道题不用状压开个数组也成的,不过状压是真的方便鸭
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
struct edge
{
int v,c,p,r,next; //分别代表目的城市,城市c,..如题
edge(){}
edge(int v,int c,int p,int r,int next):v(v),c(c),p(p),r(r),next(next){}
}e[15];
struct node
{
int cost,u; //s状态下到达u了的最小花费
int s;
node(){}
node(int cost,int u,int s):cost(cost),u(u),s(s){}
bool operator <(const node &rhs)const
{
return cost>rhs.cost; //一开始写反了,太久没用忘记了,心情复杂
}
};
int head[15];
int cnt=0;
int vis[15][1<<15];
int n,m;
typedef pair<int,int> pii;
void addedge(int u,int v,int c,int p,int r)
{
e[cnt]=edge(v,c,p,r,head[u]);
head[u]=cnt++;
}
void dijkstra()
{
memset(num,0,sizeof(num));
priority_queue<node>q;
node s(0,1,1);
q.push(s);
node tmp;
while(!q.empty())
{
tmp=q.top();
q.pop();
int u=tmp.u;
if(u==n) break;
if(vis[u][tmp.s]) continue; //注意不是要求状态只入队一次。而是状态只能扩展一次
vis[u][tmp.s]=1;
for(int i=head[u];i!=-1;i=e[i].next)
{
node now=tmp;
int v=e[i].v,c=e[i].c;
now.s|=(1<<(v-1));
if(tmp.s&(1<<(c-1))) now.cost+=e[i].p;
else now.cost+=e[i].r;
now.u=v;
q.push(now);
}
}
if(tmp.u!=n) cout<<"impossible"<<endl;
else cout<<tmp.cost<<endl;
}
int main()
{
memset(head,-1,sizeof(head));
cin>>n>>m;
for(int i=1;i<=m;++i)
{
int u,v,c,p,r;
cin>>u>>v>>c>>p>>r;
addedge(u,v,c,p,r);
}
dijkstra();
return 0;
}
感觉只要搜索登峰造极,能解决大部分dp(记忆化搜索)、博弈论(sg函数)和搜索问题emm
需要注意的是一个地方可以走多次,但是走环的话一定不是个好选择,被选次数大于n-1就一定出现环了
const int N=15;
const int INF=0x3f3f3f3f;
int n,m;
struct edge
{
int v,c,p,r;
edge(){}
edge(int v,int c,int p,int r):v(v),c(c),p(p),r(r){}
};
vector<edge>g[N];
int vis[N];
int ans=INF;
void dfs(int u,int cost)
{
if(u==n&&ans>cost)
{
ans=cost;
return ;
}
for(int i=0;i<g[u].size();++i)
{
int v=g[u][i].v,c=g[u][i].c;
if(vis[v]>n-1) continue;
vis[v]++;
if(vis[c]) dfs(v,cost+g[u][i].p);
else dfs(v,cost+g[u][i].r);
vis[v]--; //回溯
}
return ;
}
int main()
{
cin>>n>>m;
for(int i=0;i<m;++i)
{
int u,v,c,p,r;
cin>>u>>v>>c>>p>>r;
g[u].push_back(edge(v,c,p,r));
}
dfs(1,0);
if(ans==INF) cout<<"impossible"<<endl;
else cout<<ans<<endl;
return 0;
}