题目:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2369
题目大意:现在你要去机场,知道起点和终点,两种路线,商业型和经济型,商业型你只能乘一站,其他做经济型。给你m条经济型的边和k条商业型的边,并且最优解唯一。让你求出最优解的路线,打印出来,然后给出做商业型路线的那个站,最后给出最短时间。
解题思路:由于最多只有一站是商业型的路线,那么我们可以枚举这段路。其他的就是经济型的了,知道了这段路的两个端点a、b之后,加上起点到a和b到终点的最短路就是所枚举的这种情况下的最优解,然后取最小值即可。经济型的最短路,就相当于单源最短路,对起点和终点都用 dij 预处理一下就行了。注意,没两组测试数据之间要有空行。
但是,其实我第一遍不是这么做的,我的做法是做一遍两维的最短路,先给每条边加一个属性kind,0表示是经济的,1表示商业的,然后跑SPFA或dij,Node等也变为两维,0表示还没走过商业型,1表示已经走过。但是就是不知道为什么一直WA,自己造了几组数据都是对的。望高人解答!(代码见第二个)
代码如下(枚举):
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int INF = 0x0fffffff;
const int MAXN = 555;
const int MAXM = 2222<<1;
struct Edge
{
int t,v,kind,next;
}edge[MAXM];
int head[MAXN],tot;
void init()
{
tot = 0;
memset(head,-1,sizeof(head));
}
void add_edge(int s,int t,int val,int kind)
{
edge[tot].t = t;
edge[tot].v = val;
edge[tot].kind = kind;
edge[tot].next = head[s];
head[s] = tot++;
}
struct Node
{
int id,val;
bool operator < (const Node& tmp) const
{
return val > tmp.val;
}
};
priority_queue<Node> q;
int done[MAXN];
void dij(int s,int n,int* d,int* path)
{
for(int i = 1;i <= n;i++) d[i] = INF;
while(!q.empty())
q.pop();
memset(done,0,sizeof(done));
q.push((Node){s,0});
path[s] = -1;
d[s] = 0;
while(!q.empty())
{
Node cur = q.top();
q.pop();
if(done[cur.id]) continue;
for(int i = head[cur.id];i != -1;i = edge[i].next)
{
int next_id = edge[i].t;
int tmp = edge[i].v+cur.val;
if(tmp < d[next_id])
{
d[next_id] = tmp;
path[next_id] = cur.id;
q.push((Node){next_id,tmp});
}
}
}
}
int station;
void print(int& first,int u,int* path)
{
if(u == -1) return ;
print(first,path[u],path);
if(first)
{
printf("%d",u);
first = 0;
}
else printf(" %d",u);
}
void print2(int& first,int u,int* path)
{
if(u == -1) return ;
if(first)
{
printf("%d",u);
first = 0;
}
else printf(" %d",u);
print2(first,path[u],path);
}
int d[MAXN],g[MAXN];
int path_d[MAXN],path_g[MAXN];
int main()
{
int cas = 0;
int n,s,e;
while(~scanf("%d%d%d",&n,&s,&e))
{
//if(cas++) puts("");
int m;
scanf("%d",&m);
init();
while(m--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add_edge(a,b,c,0);
add_edge(b,a,c,0);
}
dij(s,n,d,path_d);
dij(e,n,g,path_g);
station = 0;
int min_val = d[e];
int aa,bb;
int k;
scanf("%d",&k);
while(k--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
int tmp = d[a]+c+g[b];
if(tmp < min_val)
{
min_val = tmp;
station = a;
aa = a;
bb = b;
}
swap(a,b);
tmp = d[a]+c+g[b];
if(tmp < min_val)
{
min_val = tmp;
station = a;
aa = a;
bb = b;
}
}
int first = 1;
if(station == 0)
{
print(first,e,path_d);
puts("");
puts("Ticket Not Used");
}
else
{
//printf("aa = %d,bb = %d\n",aa,bb);
print(first,aa,path_d);
print2(first,bb,path_g);
puts("");
printf("%d\n",station);
}
printf("%d\n",min_val);
}
return 0;
}
/*
4 1 4
4
1 2 2
1 3 3
2 4 4
3 4 5
1
2 4 3
*/
代码如下(增加状态,WA):
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int INF = 0x0fffffff;
const int MAXN = 555;
const int MAXM = 2222<<1;
struct Edge
{
int t,v,kind,next;
}edge[MAXM];
int head[MAXN],tot;
void init()
{
tot = 0;
memset(head,-1,sizeof(head));
}
void add_edge(int s,int t,int val,int kind)
{
edge[tot].t = t;
edge[tot].v = val;
edge[tot].kind = kind;
edge[tot].next = head[s];
head[s] = tot++;
}
int inq[MAXN][2];
int d[MAXN][2];
struct Node
{
int id,kind;
};
queue<Node> q;
struct Path
{
int id,kind;
}path[MAXN][2];
int ok[2];
void dij(int s,int e,int n)
{
for(int i = 1;i <= n;i++) d[i][0] = d[i][1] = INF;
while(!q.empty())
q.pop();
memset(inq,0,sizeof(inq));
ok[0] = ok[1] = 0;
q.push((Node){s,0});
inq[s][0] = 1;
path[s][0].id = -1;
d[s][0] = 0;
while(!q.empty())
{
Node cur = q.front();
q.pop();
inq[cur.id][cur.kind] = 0;
for(int i = head[cur.id];i != -1;i = edge[i].next)
{
int next_id = edge[i].t;
if(cur.kind == 1 && edge[i].kind == 1) continue;
int next_kind = cur.kind|edge[i].kind;
int tmp = edge[i].v+d[cur.id][cur.kind];
if(tmp < d[next_id][next_kind])
{
d[next_id][next_kind] = tmp;
path[next_id][next_kind] = (Path){cur.id,cur.kind};
inq[next_id][next_kind] = 1;
q.push((Node){next_id,next_kind});
}
}
}
}
int station;
void print(int& first,int u,int kind)
{
if(u == -1) return ;
if(kind == 1 && path[u][kind].kind == 0) station = path[u][kind].id;
print(first,path[u][kind].id,path[u][kind].kind);
if(first)
{
printf("%d",u);
first = 0;
}
else printf(" %d",u);
}
void solve(int s,int e,int n)
{
dij(s,e,n);
int min_val;
station = 0;
int first = 1;
if(d[e][0] < d[e][1])
{
min_val = d[e][0];
print(first,e,0);
}
else
{
min_val = d[e][1];
print(first,e,1);
}
puts("");
if(station == 0)
puts("Ticket Not Used");
else printf("%d\n",station);
printf("%d\n",min_val);
}
int main()
{
int cas = 0;
int n,s,e;
while(~scanf("%d%d%d",&n,&s,&e))
{
if(cas++) puts("");
int m;
scanf("%d",&m);
init();
while(m--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add_edge(a,b,c,0);
add_edge(b,a,c,0);
}
int k;
scanf("%d",&k);
while(k--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add_edge(a,b,c,1);
add_edge(b,a,c,1);
}
solve(s,e,n);
}
return 0;
}
/*
4 1 4
4
1 2 2
1 3 3
2 4 4
3 4 5
1
2 4
5 5 1
3
1 2 4
2 3 4
3 4 4
5
1 2 2
2 3 2
1 3 2
2 4 2
4 5 10
*/