Aizu

来源:互联网 发布:单管共射放大电路数据 编辑:程序博客网 时间:2024/05/18 00:48

传送门:AOJ  2200

题意:

你是某个岛国(ACM-ICPC Japan)上的一个苦逼程序员,你有一个当邮递员的好基友利腾桑遇到麻烦了:全岛有一些镇子通过水路和旱路相连,走水路必须要用船,在X处下船了船就停在X处。而且岛上只有一条船,下次想走水路还是得回到X处才行;两个镇子之间可能有两条以上的水路或旱路;邮递员必须按照清单上的镇子顺序送快递(镇子可能重复,并且对于重复的镇子不允许一次性处理,比如ABCB的话B一定要按顺序走两次才行)。
测试数据有多组:
N M
x1 y1 t1 sl1
x2 y2 t2 sl2

xM yM tM slM
R
z1 z2 … zR
N (2 ≤ N ≤ 200) 是镇子的数量,M (1 ≤ M ≤ 10000) 是旱路和水路合计的数量。从第2行到第M + 1行是路径的描述,路径连接xi  yi两地,路径花费 ti (1 ≤ ti ≤ 1000)时间,sli 为L时表示是旱路,S时表示是水路。可能有两条及以上路径连接两个镇子,并且路径都是双向的。
M + 2行的R是利腾需要去的镇子的数量,M + 3是利腾需要去的镇子的编号。
初始状态利腾和船都在第一个镇子,且肯定有方法达到需要去的镇子。
测试数据为0 0的时候表示终止。


正解:先floyd分别预处理只走水路和只走旱路的任意两点间的距离,然后dp求解。

dp[i][j] := 处理到第i个镇子,船停在第j个镇子里的状态下的最短路

注意这里有点容易搞混的是i代表的不是i号镇子,而是要去的目标镇子序列中第i个,但是j代表的就是j号镇子。

转移过程中注意枚举船在每个镇子的可能路径,以及不用船的路径。

还要注意的是inf不能设置成常规的0x3f3f3f3f,否则有可能爆int

代码:

#include<bits/stdc++.h>#define ll long long#define pb push_back#define fi first#define se second#define pi acos(-1)#define inf 1e8#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1#define rep(i,x,n) for(int i=x;i<n;i++)#define per(i,n,x) for(int i=n;i>=x;i--)using namespace std;typedef pair<int,int>P;const int MAXN=100010;int gcd(int a,int b){return b?gcd(b,a%b):a;}int land[202][202], sea[202][202], aim[1010];int dp[1010][202];int main(){int n, m, u, v, w;char c;while(cin >> n >> m, n + m){for(int i = 1; i <= n; i++){fill(land[i], land[i] + n + 1, inf);fill(sea[i], sea[i] + n + 1, inf);land[i][i] = sea[i][i] = 0;} while(m--){scanf("%d %d %d %c", &u, &v, &w, &c);if(c == 'S')sea[u][v] = sea[v][u] = min(sea[v][u], w);elseland[u][v] = land[v][u] = min(land[v][u], w);}cin >> m;for(int i = 1; i <= m; i++){scanf("%d", aim + i);}for(int i = 0; i <= m; i++)fill(dp[i], dp[i] + n + 1, inf);for(int k = 1; k <= n; k++)for(int i = 1; i <= n; i++)for(int j = 1; j <= n; j++){land[i][j] = min(land[i][j], land[i][k] + land[k][j]);sea[i][j] = min(sea[i][j], sea[i][k] + sea[k][j]);}dp[1][aim[1]] = 0;for(int i = 1; i <= m; i++)//枚举处理到了第几个aim for(int j = 1; j <= n; j++)//枚举上一次船停的位置{dp[i][j] = min(dp[i][j], dp[i - 1][j] + land[aim[i - 1]][aim[i]]);//接着走旱路到达aim[i]for(int k = 1; k <= n; k++)//枚举这一次船停的位置 {dp[i][k] = min(dp[i][k], dp[i - 1][j] + land[aim[i - 1]][j] + sea[j][k] + land[k][aim[i]]);}}cout << *min_element(dp[m] + 1, dp[m] + n + 1) << endl;} return 0;}


其实整个题就全是dp,因为floyd 的本质不就是dp嘛。