题目链接:https://vjudge.net/problem/UVA-1048
题意:给定一些联票,在给定一些行程,要求这些行程的最小代价
解法:
#include <bits/stdc++.h>
using namespace std;
const int Max_City = 200;
const int Max_Ticket = 20;
const int Max_TicketLength = 10;
const int Max_TripLength = 10;
struct Info{
int cost,n;
int city[Max_TicketLength];
};
int N, n, q, trip, sum;//路线编号为trip,sum为总的城市数,n为某条旅行路线的长度
int city[Max_City];//城市序列
int List[Max_TripLength];//当前最小旅游费用路线上第i个到达的城市为List[i]
Info ticket[Max_Ticket];
int f[Max_TripLength][Max_City][4];//途径当前路线的前n个城市,
//最后到达城市m时,最小花费为f[n][m][0]
//最后使用的机票编号为f[n][m][1],
//使用本机票前途径的城市数为f[n][m][2],开始使用本机票的城市为f[n][m][3]
int route[Max_TicketLength*Max_City];//当期路线使用的机票序列
int Find(int x){
int i;
for(i=0;i<sum;i++) if(city[i]==x) return i;
city[sum]=x;
sum++;
return (sum-1);
}
int main(){
int ks = 0;
while(scanf("%d", &N)!=EOF){
if(N==0) break;
sum=0;
int tmp;
for(int i=0; i<N; i++){
scanf("%d %d", &ticket[i].cost,&ticket[i].n);
for(int j=0; j<ticket[i].n; j++){
scanf("%d", &tmp);
ticket[i].city[j] = Find(tmp);
}
}
++ks;
scanf("%d", &q);
for(trip=0; trip<q; trip++){
scanf("%d", &n);
for(int i=0; i<n; i++){
scanf("%d", &tmp);
List[i] = Find(tmp);
}
//init
for(int i=0; i<n; i++)
for(int j=0; j<sum; j++)
f[i][j][0] = -1;
for(int i=0; i<4; i++)
f[0][List[0]][i] = 0;
//递推路线上到达的城市数
for(int i=0; i<n; i++){
while(1){
bool change = 0;//更新标志初始化
for(int j=0; j<sum; j++)//枚举旅行者目前在的城市
if(f[i][j][0]>=0)//若已经求出到城市j的最小花费
for(int k=0; k<N; k++)//枚举在城市j开始换用的机票k
if(ticket[k].city[0]==j){
tmp=i+1;
//从当前路线的第i+1个城市出发,枚举使用优惠机票k可到达路线上的每个城市
for(int l=1;l<ticket[k].n; l++){
if(tmp<n&&List[tmp]==ticket[k].city[l]) tmp++;
if(f[tmp-1][ticket[k].city[l]][0]<0||f[tmp-1][ticket[k].city[l]][0]>f[i][j][0]+ticket[k].cost){
f[tmp-1][ticket[k].city[l]][0] = f[i][j][0]+ticket[k].cost;
f[tmp-1][ticket[k].city[l]][1] = k;
f[tmp-1][ticket[k].city[l]][2] = i;
f[tmp-1][ticket[k].city[l]][3] = j;
change=1;
}
}
}
if(change==0) break;
}
}
printf("Case %d, Trip %d: Cost = %d\n", ks, trip+1, f[n-1][List[n-1]][0]);
int l=0;
int k,i=n-1,j=List[n-1];
while(i||j!=List[0]){
route[l]= f[i][j][1];//记下当前的机票编号
k = f[i][j][2];//记下使用本机票前到过的城市数
j = f[i][j][3];//记下使用本机票前旅行者在的城市
i = k;
l++;
}
printf(" Tickets used:");
for(i=l-1; i>=0; i--){
printf(" %d", route[i]+1);
}
printf("\n");
}
}
}