题意:给你N个点M条边的的图,边分为旱路和水路,水路需要用船才能经过,当你不用船时,你会把船停在那个结点,现在你有个任务:你需要依次经过一些点,开始你和船都在任务里的1号结点,问完成任务的最小代价
题解:
dp+floyd
N只有200,可以用floyd跑出旱路和水路两两之间的最短路
然后就可以n×n×cnt(任务数)的用dp转移了
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 #define ll long long 8 using namespace std; 9 10 const int N = 210; 11 12 int n,m,cnt,ans,p[1010],dis[N][N][2],dp[1010][N]; 13 14 int gi() { 15 int x=0,o=1; char ch=getchar(); 16 while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar(); 17 if(ch=='-') o=-1,ch=getchar(); 18 while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); 19 return o*x; 20 } 21 22 void init() { 23 ans=1<<30; 24 for(int i=0; i<=n; i++) 25 for(int j=0; j<=n; j++) 26 for(int k=0; k<2; k++) 27 dis[i][j][k]=1e8; 28 } 29 30 void floyd() { 31 for(int t=0; t<2; t++) 32 for(int k=1; k<=n; k++) 33 for(int i=1; i<=n; i++) 34 for(int j=1; j<=n; j++) 35 dis[i][j][t]=min(dis[i][j][t],dis[i][k][t]+dis[k][j][t]); 36 } 37 38 int main() { 39 while(scanf("%d%d", &n, &m) && n+m) { 40 init(); 41 for(int i=1; i<=m; i++) { 42 int x=gi(),y=gi(),z=gi(); char ch; 43 scanf("%c", &ch); 44 if(ch=='L') dis[x][y][0]=dis[y][x][0]=min(dis[x][y][0],z); 45 else dis[x][y][1]=dis[y][x][1]=min(dis[x][y][1],z); 46 } 47 cnt=gi(); 48 for(int i=1; i<=cnt; i++) p[i]=gi(); 49 for(int i=1; i<=n; i++) dis[i][i][0]=dis[i][i][1]=0; 50 floyd(); 51 for(int i=0; i<=cnt; i++) 52 for(int j=0; j<=n; j++) 53 dp[i][j]=1e8; 54 dp[1][p[1]]=0; 55 for(int i=1; i<=cnt; i++) 56 for(int j=1; j<=n; j++) { 57 dp[i][j]=min(dp[i][j],dp[i-1][j]+dis[p[i-1]][p[i]][0]); 58 for(int k=1; k<=n; k++) { 59 dp[i][k]=min(dp[i][k],dp[i-1][j]+dis[p[i-1]][j][0]+dis[j][k][1]+dis[k][p[i]][0]); 60 } 61 } 62 for(int i=1; i<=n; i++) ans=min(ans,dp[cnt][i]); 63 printf("%d ", ans); 64 } 65 return 0; 66 }