poj 2387
全裸的最短路,随便什么算法都能过
Poj 2253
这题可以用最小生成树来做,kruskal搞一下,如果1-2连同,此时的边就是青蛙跳的最大距离
while(scanf("%d",&n)&&n){
kase++;
int xcount=0;
for(int i=1;i<=n;i++) pre[i]=i;
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i],&b[i]);
for(int j=1;j<i;j++){
p[xcount].from=j;
p[xcount].to=i;
p[xcount++].cost=sqrt(double((a[i]-a[j])*(a[i]-a[j])+(b[i]-b[j])*(b[i]-b[j])));
}
}
sort(p,p+xcount,cmp);
for(int i=0;i<xcount;i++){
Union(p[i].from,p[i].to);
if(Find(1)==Find(2)){
printf("Scenario #%d\nFrog Distance = %.3lf\n\n",kase,p[i].cost);
break;
}
}
}
poj 1797
这个题是求1-n的路中,最小边最大的一条路,可以用spfa变化下求。
dis[k]=max(dis[k],min(dis[x],edge[x][k]));
void spfa(int u){
queue<int> q;
q.push(u);
vis[u]=1;
dis[u]=INF;
while(!q.empty()){
int x=q.front();
q.pop();
vis[x]=0;
for(int i=0;i<v[x].size();i++){
int k=v[x][i];
if(dis[k]<min(dis[x],edge[x][k])){
dis[k]=min(dis[x],edge[x][k]);
if(!vis[k]){
vis[k]=1;
q.push(k);
}
}
}
}
}
poj 3268
题意:给你m个有向边,n个牛先从自己家去x点,再回去,问哪个牛走的最长
题解:把给的有向边正着存一份,以x为源点求最短路,可以得到每个牛回家的距离。
再把所有有向边都倒过来存一遍,以x为源点求最短路,得到的是每个牛去的时候的距离。
想加找最大即可,两次spfa的事。
poj3259
题意:这题难点就在于读题。有m条无向的路,还有w条有向的路(虫洞),A one way path from S to E that also moves the traveler back T seconds.意思是这条有向边的权值是负的,然后要求的是FJ能否回到起点,意思就是说有没有负环,如果有负环的话,他会一直在那个负环里转,因为权值每次都变小了。
题解:用spfa(bellman-ford)求负环即可
vector<int> v[505];
int edge[505][505];
int dis[505];
int vis[505];
int xcount[505];
int n,m,w;
void spfa(int u){
queue<int> q;
q.push(u);
vis[u]=1;
dis[u]=0;
xcount[u]++;
while(!q.empty()){
int x=q.front();
q.pop();
vis[x]=0;
for(int i=0;i<v[x].size();i++){
int k=v[x][i];
if(dis[k]>dis[x]+edge[x][k]){
dis[k]=dis[x]+edge[x][k];
if(!vis[k]){
vis[k]=1;
q.push(k);
xcount[k]++;
if(xcount[k]>n){
printf("YES\n");
return;
}
}
}
}
}
printf("NO\n");
}
POJ 1502
题意:这题又是英语来卡人,是说从1到各个点的最短路中的最大值,说到这里就是个水题了,然而看懂题目才是最难的。
poj 3660
题意:这题是给你m个有向边的关系,还有个确定有多少个牛的位置确定了
题解:Floyd暴力一遍,把所有有向边的关系都确定了,然后枚举每个牛,看他的入度出度之和是否为n-1
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(edge[i][k]&&edge[k][j]) edge[i][j]=1;
}
}
}
int ans=0;
for(int i=1;i<=n;i++){
int flag=0;
for(int j=1;j<=n;j++){
if(i==j) continue;
if(!(edge[i][j]||edge[j][i])) flag=1;
}
if(!flag) ans++;
}
printf("%d\n",ans);
poj 1511
这题就是个很显然的最短路,题目辣么长,然而难点在于数据量大!!!100w
题解:可以用dijkstra的堆优化和spfa来做。(刚学堆优化写的挫)
#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <stack>
using namespace std;
#define MAX 1000000+5
#define MAXN 100000+5
typedef long long LL;
typedef unsigned long long ull;
const double pi=3.141592653589793;
const int INF=0x3f3f3f3f;
const int INFF=1e9;
const double inf=1e18;
const double eps=1e-10;
const int mod=1000000007;
const int prime=999983;
struct edge{
int v,cost;
edge(){}
edge(int _v,int _cost):v(_v),cost(_cost){}
};
struct edge2{
int u,v,w;
edge2(){}
edge2(int _u,int _v,int _w):u(_u),v(_v),w(_w){}
}a[MAX];
struct node{
int id,val;
node(){}
node(int _id,int _v):id(_id),val(_v){}
bool operator <(const node &a)const{ //重载<,使优先队列队首始终是val最小的元素
return val>a.val;
}
}x,y;
vector<edge> v[MAX];
int vis[MAX];
int dis[MAX];
int n,m;
LL dijkstra(int s){
priority_queue<node> q;
memset(vis,0,sizeof(vis));
memset(dis,INF,sizeof(dis));
x.id=s;
x.val=0;
dis[s]=0;
q.push(x);
while(!q.empty()){
x=q.top();
q.pop();
int num=x.id;
if(vis[num]) continue;
vis[num]=1;
for(int i=0;i<v[num].size();i++){
int to=v[num][i].v;
int cost=v[num][i].cost;
if(!vis[to]&&dis[to]>dis[num]+cost){
dis[to]=dis[num]+cost;
y.id=to;
y.val=dis[to];
q.push(y);
}
}
}
LL sum=0;
for(int i=1;i<=n;i++) sum+=dis[i];
return sum;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
LL ans=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) v[i].clear();
for(int i=1;i<=m;i++){
int u,vv,w;
scanf("%d%d%d",&u,&vv,&w);
a[i]=edge2(u,vv,w);
v[u].push_back(edge(vv,w));
}
ans+=dijkstra(1);
for(int i=1;i<=n;i++) v[i].clear();
for(int i=1;i<=m;i++){
int u = a[i].u;
int vv = a[i].v;
int w = a[i].w;
v[vv].push_back(edge(u,w));
}
ans+=dijkstra(1);
printf("%lld\n",ans);
}
return 0;
}
下面是spfa的算法:时间复杂度和dijkstra的差不多(我以前用了LL 果断T了10次+)存结构体这种方法非常好,get
#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <stack>
using namespace std;
#define MAX 1000000+5
#define MAXN 100000+5
typedef long long LL;
typedef unsigned long long ull;
const double pi=3.141592653589793;
const int INF=0x3f3f3f3f;
const int INFF=1e9;
const double inf=1e18;
const double eps=1e-10;
const int mod=1000000007;
const int prime=999983;
struct edge{
int v,cost;
edge(){}
edge(int _v,int _c):v(_v),cost(_c){}
};
struct edge2{
int u,v,w;
edge2(){}
edge2(int _u,int _v,int _w):u(_u),v(_v),w(_w){}
}a[MAX];
vector<edge> v[MAX];
int dis[MAX];
int vis[MAX];
int n,m;
LL spfa(int s){
queue<int> q;
memset(dis,INF,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[s]=0;
vis[s]=1;
q.push(s);
while(!q.empty()){
int x=q.front();
q.pop();
vis[x]=0;
for(int i=0;i<v[x].size();i++){
int k=v[x][i].v;
int cost=v[x][i].cost;
if(dis[k]>dis[x]+cost){
dis[k]=dis[x]+cost;
if(!vis[k]){
vis[k]=1;
q.push(k);
}
}
}
}
LL sum=0;
for(int i=1;i<=n;i++) sum+=dis[i];
return sum;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
LL ans=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) v[i].clear();
for(int i=1;i<=m;i++){
int u,vv,w;
scanf("%d%d%d",&u,&vv,&w);
a[i]=edge2(u,vv,w);
v[u].push_back(edge(vv,w));
}
ans+=spfa(1);
for(int i=1;i<=n;i++) v[i].clear();
for(int i=1;i<=m;i++){
int u = a[i].u;
int vv = a[i].v;
int w = a[i].w;
v[vv].push_back(edge(u,w));
}
ans+=spfa(1);
printf("%lld\n",ans);
}
return 0;
}
poj 3159
题意:给你a,b,c三个数意思是a认为b不能比他多c个糖,p[b]-p[a]<=c,即为 p[b]<=p[a]+c,这就是显然的最短路,详见差分约束系统http://blog.csdn.net/xuezhongfenfei/article/details/8685313
题解:这题就是数据量大,用vector建图过不了,用dijkstra+heap+前向星可以过,spfa+stack也轻松掠过。答案就是求p[n]-p[1]的最大值,即dis[n](感觉我差分也没全搞懂,改天还得学学)(dijkstra和spfa复杂度接近)
spfa+stack
#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <stack>
using namespace std;
#define MAX 30000+5
#define MAXN 100000+5
typedef long long LL;
typedef unsigned long long ull;
const double pi=3.141592653589793;
const int INF=0x3f3f3f3f;
const int INFF=1e9;
const double inf=1e18;
const double eps=1e-10;
const int mod=1000000007;
const int prime=999983;
struct Edge{
int v,cost,next;
}edge[150005];
struct node{
int id,val;
bool operator<(const node &a)const{
return val>a.val;
}
}x;
int head[30005];
int dis[30005];
int vis[30005];
int sstack[30005];
int tot;
inline int read_int()
{
int ret=0;
char tmp;
while(!isdigit(tmp=getchar()));
do{
ret=(ret<<3)+(ret<<1)+tmp-'0';
}while(isdigit(tmp=getchar()));
return ret;
}
void add_edge(int a,int b,int c){
edge[tot].v=b;
edge[tot].cost=c;
edge[tot].next=head[a];
head[a]=tot++;
}
void spfa(int s){
memset(vis,0,sizeof(vis));
memset(dis,INF,sizeof(dis));
int top=0;
sstack[top++]=s;
dis[s]=0;
vis[s]=1;
while(top!=0){
int q=sstack[--top];
vis[q]=0;
for(int i=head[q];i!=-1;i=edge[i].next){
int v=edge[i].v;
int cost=edge[i].cost;
if(dis[v]>dis[q]+cost){
dis[v]=dis[q]+cost;
if(!vis[v]){
vis[v]=1;
sstack[top++]=v;
}
}
}
}
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
tot=0;
for(int i=0;i<m;i++){
int a=read_int();
int b=read_int();
int c=read_int();
add_edge(a,b,c);
}
spfa(1);
printf("%d\n",dis[n]);
return 0;
}
dijkstra+heap
#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <stack>
using namespace std;
#define MAX 30000+5
#define MAXN 100000+5
typedef long long LL;
typedef unsigned long long ull;
const double pi=3.141592653589793;
const int INF=0x3f3f3f3f;
const int INFF=1e9;
const double inf=1e18;
const double eps=1e-10;
const int mod=1000000007;
const int prime=999983;
struct Edge{
int v,cost,next;
}edge[150005];
struct node{
int id,val;
bool operator<(const node &a)const{
return val>a.val;
}
}x;
int head[30005];
int dis[30005];
int vis[30005];
int tot;
inline int read_int()
{
int ret=0;
char tmp;
while(!isdigit(tmp=getchar()));
do{
ret=(ret<<3)+(ret<<1)+tmp-'0';
}while(isdigit(tmp=getchar()));
return ret;
}
void add_edge(int a,int b,int c){
edge[tot].v=b;
edge[tot].cost=c;
edge[tot].next=head[a];
head[a]=tot++;
}
void dijkstra(int s){
memset(vis,0,sizeof(vis));
memset(dis,INF,sizeof(dis));
priority_queue<node> q;
x.id=s;
x.val=0;
dis[s]=0;
q.push(x);
while(!q.empty()){
x=q.top();
q.pop();
int num=x.id;
if(vis[num]) continue;
vis[num]=1;
for(int i=head[num];i!=-1;i=edge[i].next){
int vv=edge[i].v;
int cost=edge[i].cost;
if(!vis[vv]&&dis[vv]>dis[num]+cost){
dis[vv]=dis[num]+cost;
x.id=vv;
x.val=dis[vv];
q.push(x);
}
}
}
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
tot=0;
for(int i=0;i<m;i++){
int a=read_int();
int b=read_int();
int c=read_int();
add_edge(a,b,c);
}
dijkstra(1);
printf("%d\n",dis[n]);
return 0;
}
poj 1062
题意:一个比较明显的最短路,加上了等级。
题解:枚举最高等级,然后把等级不满足的点直接vis[x]=1记作已经访问过。
然后dijkstra即可
for(int i=mini;i<=maxn;i++){
memset(vis,0,sizeof(vis));
memset(dis,INF,sizeof(dis));
for(int j=1;j<=n;j++){
if(level[j]>i||i-level[j]>m) vis[j]=1;
}
dis[0]=0;
while(1){
int x=n+1;
for(int i=0;i<=n;i++){
if(!vis[i]&&dis[i]<dis[x]) x=i;
}
if(x==n+1) break;
vis[x]=1;
for(int i=0;i<=n;i++){
if(!vis[i]) dis[i]=min(dis[i],dis[x]+edge[x][i]);
}
}
ans=min(ans,dis[1]);
}
printf("%d\n",ans);
lightoj 1074
题意:很明显是最短路哇
题解:spfa判下负环即可。水水哒
/**********************************************************************************************************************************************************************************/
HDU 4370(转自kuangbin大神blog)(绝对好题***)
显然,题目给的是一个0/1规划模型。
解题的关键在于如何看出这个模型的本质。
3个条件明显在刻画未知数之间的关系,从图论的角度思考问题,容易得到下面3个结论:
1.X12+X13+...X1n=1 于是1号节点的出度为1
2..X1n+X2n+...Xn-1n=1 于是n号节点的入度为1
3.∑Xki =∑Xij 于是2~n-1号节点的入度必须等于出度
于是3个条件等价于一条从1号节点到n号节点的路径,故Xij=1表示需要经过边(i,j),代价为Cij。Xij=0表示不经过边(i,j)。注意到Cij非负且题目要求总代价最小,因此最优答案的路径一定可以对应一条简单路径。
最终,我们直接读入边权的邻接矩阵,跑一次1到n的最短路即可,记最短路为path。
以上情况设为A
非常非常非常非常非常非常非常非常抱歉,简单路径只是充分条件,但不必要。(对造成困扰的队伍深表歉意)
漏了如下的情况B:
从1出发,走一个环(至少经过1个点,即不能是自环),回到1;从n出发,走一个环(同理),回到n。
容易验证,这是符合题目条件的。且A || B为该题要求的充要条件。
由于边权非负,于是两个环对应着两个简单环。
本程序用SPFA来完成最短路。
但是由于要计算从出发点出发的闭环的路径长度。
所以要在普通SPFA的基础上做点变化。
就是把dist[start]设为INF。同时一开始并不是让出发点入队,而是让
出发点能够到达的点入队。
故最终答案为min(path,c1+c2)(用前向星建图比较好)
<span style="font-size:12px;">#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <stack>
using namespace std;
#define MAX 30000+5
#define MAXN 100000+5
typedef long long LL;
typedef unsigned long long ull;
const double pi=3.141592653589793;
const int INF=0x3f3f3f3f;
const int INFF=1e9;
const double inf=1e18;
const double eps=1e-10;
const int mod=1000000007;
const int prime=999983;
inline int read_int()
{
int ret=0;
char tmp;
while(!isdigit(tmp=getchar()));
do{
ret=(ret<<3)+(ret<<1)+tmp-'0';
}while(isdigit(tmp=getchar()));
return ret;
}
struct Edge{
int v,cost,next;
}edge[100000];
int head[305];
int dis[305];
int vis[305];
int tot;
void add_edge(int a,int b,int c){
edge[tot].v=b;
edge[tot].cost=c;
edge[tot].next=head[a];
head[a]=tot++;
}
void spfa(int s){
memset(vis,0,sizeof(vis));
memset(dis,INF,sizeof(dis));
queue<int> q;
for(int i=head[s];i!=-1;i=edge[i].next){
int k=edge[i].v;
if(k!=s){
dis[k]=edge[i].cost;
vis[k]=1;
q.push(k);
}
}
while(!q.empty()){
int x=q.front();
q.pop();
vis[x]=0;
for(int i=head[x];i!=-1;i=edge[i].next){
int k=edge[i].v;
int cost=edge[i].cost;
if(dis[k]>dis[x]+cost){
dis[k]=dis[x]+cost;
if(!vis[k]){
vis[k]=1;
q.push(k);
}
}
}
}
}
int main(){
int n;
while(~scanf("%d",&n)){
memset(edge,INF,sizeof(edge));
memset(head,-1,sizeof(head));
tot=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
int a;
scanf("%d",&a);
add_edge(i,j,a);
}
}
spfa(1);
int path=dis[n];
int c1=dis[1];
spfa(n);
int c2=dis[n];
printf("%d\n",min(path,c1+c2));
}
return 0;
}
poj 3169
题意:当排队等候喂食时,奶牛喜欢和它们的朋友站得靠近些。FJ有N(2<=N<=1000)头奶牛,编号从1到N,沿一条直线站着等候喂食。奶牛排在队伍中的顺序和它们的编号是相同的。因为奶牛相当苗条,所以可能有两头或者更多奶牛站在同一位置上。即使说,如果我们想象奶牛是站在一条数轴上的话,允许有两头或更多奶牛拥有相同的横坐标。
一些奶牛相互间存有好感,它们希望两者之间的距离不超过一个给定的数L。另一方面,一些奶牛相互间非常反感,它们希望两者间的距离不小于一个给定的数D。给出ML条关于两头奶牛间有好感的描述,再给出MD条关于两头奶牛间存有反感的描述。(1<=ML,MD<=10000,1<=L,D<=1000000)
你的工作是:如果不存在满足要求的方案,输出-1;如果1号奶牛和N号
奶牛间的距离可以任意大,输出-2;否则,计算出在满足所有要求的情况下,1号奶牛和N号奶牛间可能的最大距离。
题解:这题给出了一些好感的关系,首先题目说每个牛站的位置是按照标号顺序的,所以3号的位置肯定大于等于1号。
所以一种情况就是AB最大相差C,就是B-A<=C,即为B<=A+C,这是A->B之间有一条权值C的有向边。
AB相差最小为C,就是B-A>=C,即为B>=A+C,化成A<=B-C,这是B->A之间有一条权值为-C的有向边
建图之后spfa跑一遍(因为有负权值),如果dis[n]==INF的时候就是1-n之间的没有最短路,可以任意距离,输出-2
有负环就是-1这个队伍不能排(我一开始-1 -2搞反了)
<span style="font-size:12px;">#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <stack>
using namespace std;
#define MAX 30000+5
#define MAXN 100000+5
typedef long long LL;
typedef unsigned long long ull;
const double pi=3.141592653589793;
const int INF=0x3f3f3f3f;
const int INFF=1e9;
const double inf=1e18;
const double eps=1e-10;
const int mod=1000000007;
const int prime=999983;
inline int read_int()
{
int ret=0;
char tmp;
while(!isdigit(tmp=getchar()));
do{
ret=(ret<<3)+(ret<<1)+tmp-'0';
}while(isdigit(tmp=getchar()));
return ret;
}
struct Edge{
int v,cost,next;
}edge[20000];
int head[1005];
int dis[1005];
int vis[1005];
int xcount[1005];
int tot;
int flag;
void add_edge(int a,int b,int c){
edge[tot].v=b;
edge[tot].cost=c;
edge[tot].next=head[a];
head[a]=tot++;
}
void spfa(int s,int n){
memset(vis,0,sizeof(vis));
memset(dis,INF,sizeof(dis));
memset(xcount,0,sizeof(xcount));
queue<int> q;
dis[s]=0;
vis[s]=1;
xcount[s]++;
q.push(s);
while(!q.empty()){
int x=q.front();
q.pop();
vis[x]=0;
for(int i=head[x];i!=-1;i=edge[i].next){
int k=edge[i].v;
int cost=edge[i].cost;
//printf("%d %d %d \n",x,k,cost);
if(dis[k]>dis[x]+cost){
dis[k]=dis[x]+cost;
if(!vis[k]){
vis[k]=1;
xcount[k]++;
q.push(k);
if(xcount[k]>n){
flag=1;
return ;
}
}
}
}
}
}
int main(){
int n,l,d;
scanf("%d%d%d",&n,&l,&d);
tot=0;
memset(head,-1,sizeof(head));
for(int i=0;i<l;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add_edge(a,b,c);
}
for(int i=0;i<d;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add_edge(b,a,-c);
}
flag=0;
spfa(1,n);
if(flag) printf("-1\n");
else if(dis[n]==INF) printf("-2\n");
else printf("%d\n",dis[n]);
return 0;
}
</span>
hdu 4725
题意:给你n个点,每个点属于某个层,点之间有m条无向边,相邻的层之间还能互相走,花费是c
题解:首先看百度上说要拆点,后来学长没用拆点就过去了。
记录每个层有哪些点,然后用dijkstra+heap的时候,点的结构体中要加个判断is_node,如果是点,他就可以走向他所连的边,还有他的上一层或者下一层,都进队。
如果是层,那么可以把这层上的所有点(未访问过并且dis被更新过的)放进队列中,即可。(前向星建图head没有初始化又看了好久,还得多练,这题也是虚掉了不敢做,so weak)
#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <stack>
using namespace std;
#define MAX 30000+5
#define MAXN 100000+5
typedef long long LL;
typedef unsigned long long ull;
const double pi=3.141592653589793;
const int INF=0x3f3f3f3f;
const int INFF=1e9;
const double inf=1e18;
const double eps=1e-10;
const int mod=1000000007;
const int prime=999983;
inline int read_int(){
int ret=0;
char tmp;
while(!isdigit(tmp=getchar()));
do{
ret=(ret<<3)+(ret<<1)+tmp-'0';
}while(isdigit(tmp=getchar()));
return ret;
}
struct Node{
int v,val;
bool is_node;
bool operator < (const Node &a)const{
return val > a.val;
}
};
struct Edge{
int v,cost,next;
}edge[2*MAXN];
int n,m,c;
vector<int> v[MAXN];
int lay[MAXN];
int head[MAXN];
int dis[MAXN];
int vis[MAXN];
int vis_l[MAXN];
int tot;
int max_l,min_l;
void add_edge(int a,int b,int c){
edge[tot]=(Edge){b,c,head[a]};
head[a]=tot++;
}
void dijkstra(int s){
memset(vis,0,sizeof(vis));
memset(vis_l,0,sizeof(vis_l));
memset(dis,INF,sizeof(dis));
priority_queue<Node> q;
q.push((Node){s,0,1});
dis[s]=0;
while(!q.empty()){
Node now=q.top();
q.pop();
int num=now.v;
if(now.is_node){
if(vis[num]) continue;
vis[num]=1;
for(int i=head[num];i!=-1;i=edge[i].next){
int k=edge[i].v;
int cost=edge[i].cost;
if(!vis[k]&&dis[k]>dis[num]+cost){
dis[k]=dis[num]+cost;
q.push((Node){k,dis[k],1});
}
}
if(lay[num]>min_l){
q.push((Node){lay[num]-1,dis[num]+c,0});
}
if(lay[num]<max_l){
q.push((Node){lay[num]+1,dis[num]+c,0});
}
}
else{
if(vis_l[num]) continue;
vis_l[num]=1;
for(int i=0;i<v[num].size();i++){
int k=v[num][i];
if(!vis[k]&&dis[k]>now.val){
dis[k]=now.val;
q.push((Node){k,dis[k],1});
}
}
}
}
}
int main(){
int T;
scanf("%d",&T);
for(int t=1;t<=T;t++){
scanf("%d%d%d",&n,&m,&c);
tot=0;
max_l=0;
min_l=INF;
memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++) v[i].clear();
for(int i=1;i<=n;i++){
scanf("%d",&lay[i]);
v[lay[i]].push_back(i);
max_l=max(max_l,lay[i]);
min_l=min(min_l,lay[i]);
}
for(int i=0;i<m;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add_edge(a,b,c);
add_edge(b,a,c);
}
dijkstra(1);
printf("Case #%d: ",t);
if(dis[n]==INF) printf("-1\n");
else printf("%d\n",dis[n]);
}
return 0;
}
还有个神马最短路+最大流还不会,改天做完了再发