题意 : n个城市,每个城市的油价不同,m条连通这些城市之间的路,提供油桶的容量,要你求出由城市s出发到城市e的最小费用,其中刚开始时油桶为空,一单位的油可以走以单位的长度。 看到这题目觉得很难,这主要是不会建图和DP的思想. 事实上就是类似dijsktra算法的搜索,搜索最短路。 这个题目的图的点事实上有两个维. 一个是费用,一个是地点,(比如在位置0有1升油是一个点,在位置0有2升油又是另外一个点) 如果把这种点抽象出来,把费用看过边,那么最少费用就可以按照dijsktra算法那样不断的加入点(至于正确性请看dijkstra算法的证明,贪心性质,非负权边) 于是得到一个扩展结点的策略: 1.每一次加一升油(因为题目的条件这些都是整数,所以可以类似离散化处理,一点一点加入油) 2.如果加的油足够走到下一个结点,那就走到下一个结点吧(记得减去路上消耗的油,还有花费不变...) #include<iostream> #include<cmath> #include<queue> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> using namespace std; #define inf 0x7fffffff const int MAX=1002; struct EDGE { int v;//终点 int len;//边的长度 int next; }edge[10009];//一定要边的范围 int head[MAX]; int k; int n,m; int S,V,E; int a[1003]; int dp[1002][102]; bool used[1002][102]; void insert(int u,int v,int len) { edge[k].v=v; edge[k].len=len; edge[k].next=head[u]; head[u]=k; k++;//正边 edge[k].v=u; edge[k].len=len; edge[k].next=head[v]; head[v]=k; k++;//反边 } struct Node { int posion; int vale; int fule; friend bool operator <(Node a,Node b) { return a.vale>b.vale; } }; priority_queue<Node>my; Node next,now; int dij(int s) { while(!my.empty()) my.pop(); memset(used,0,sizeof(used)); for(int i=1;i<=n;i++) for(int j=0;j<=100;j++) dp[i][j]=inf; now.posion=s; now.fule=0; now.vale=0; my.push(now); dp[s][0]=0; used[s][0]=1; while(!my.empty()) { now=my.top(); my.pop(); int x=now.posion; int y=now.fule; int z=now.vale; used[x][y]=1; if(x==E) return z; if(y+1<=V&&!used[x][y+1]&&dp[x][y+1]>dp[x][y]+a[x]) { dp[x][y+1]=dp[x][y]+a[x]; next.fule=y+1; next.posion=x; next.vale=dp[x][y+1]; my.push(next); } for(int i=head[x];i!=-1;i=edge[i].next) { int t=edge[i].v; int kk=y-edge[i].len; if(kk>=0&&!used[t][kk]&&z<dp[t][kk]) { dp[t][kk]=z; next.posion=t; next.fule=kk; next.vale=dp[t][kk]; my.push(next); } } } return -1; } int ans; int uu,vv,cc; int cas; int main() { int i; scanf("%d%d",&n,&m); { for( i=1;i<=n;i++) head[i]=-1; k=0; for( i=1;i<=n;i++) scanf("%d",&a[i]); for( i=0;i<m;i++) { scanf("%d%d%d",&uu,&vv,&cc); uu++;vv++; insert(uu,vv,cc); } // for(int x=1;x<=n;x++) // for(int i=head[x];i!=-1;i=edge[i].next) // { // cout<<x<<' '<<edge[i].v<<' '<<edge[i].len<<endl; // } scanf("%d",&cas); while(cas--) { scanf("%d%d%d",&V,&S,&E);; S++;E++; ans=dij(S); if(ans==-1) printf("impossible"); else printf("%d\n",ans); } } return 0; }