zoukankan      html  css  js  c++  java
  • AOJ 2200 Mr. Rito Post Office (floyd+DP)

    题意:

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

    测试数据有多组:

    N M

    x1 y1 t1 sl1

    x2 y2 t2 sl2

    xM yM tM slM

    R

    z1 z2zR

    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预处理出单独走水路s或陆路l的两两之间的最短路。

    d[i][j]表示到序列第i点时船停在j,已经去了第i个镇子后,船停在第j个镇子里的状态下的最短路。

    状态转移:人从a到b,船从c到d,若船动加上l[a,c]+s[c,d]+l[d,b],若船不动则只要加上l[a][b]。

    然后ijk三重循环更新dp,其中递推公式思路:

    在推导ik的时候,定义一个中间状态j表示先从i-1走旱路到j,然后从j走水路去k,最后从k走旱路去i,于是就把船扔在了k。

    如果j==k的时候就不需要绕圈子了。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    int s[210][210];//水路
    int l[210][210];//陆路
    int d[1010][210];//dp
    int b[1010];//目标路线
    
    const int INF = 0x3f3f3f3f;
    
    void Floyd(int n) 
    {
    	for (int k = 1; k <= n; ++k) 
    	{
    		for (int i = 1; i <= n; ++i) 
    		{
    			for (int j = 1; j <= n; ++j) 
    			{
    				s[i][j] = min(s[i][j], s[i][k] + s[k][j]);
    				l[i][j] = min(l[i][j], l[i][k] + l[k][j]);
    			}
    		}
    	}
    }
    
    int main() 
    {
    	int n, m, r;
    	int u, v, c;
    	char tp[2];
    
    	while (scanf("%d%d", &n, &m) != EOF && n) 
    	{
    		memset(s, INF, sizeof(s));
    		memset(l, INF, sizeof(l));
    		memset(d, INF, sizeof(d));
    
    		while (m--) 
    		{
    			scanf("%d%d%d%s", &u, &v, &c, tp);
    			if (tp[0] == 'L') 
    			{
    				l[u][v] = min(l[u][v], c);
    				l[v][u] = min(l[v][u], c);
    			}
    			else 
    			{
    				s[u][v] = min(s[u][v], c);
    				s[v][u] = min(s[v][u], c);
    			}
    		}
    
    		for (int i = 1; i <= n; ++i) 
    		{
    			l[i][i] = 0;
    			s[i][i] = 0;
    		}
    
    		scanf("%d", &r);
    
    		for (int i = 1; i <= r; ++i) 
    		{
    			scanf("%d", &b[i]);
    		}
    
    		Floyd(n);
    
    		for (int i = 1; i <= n; ++i) 
    		{
    			d[1][i] = min(d[1][i], s[b[1]][i] + l[i][b[1]]);
    		}
    
    		for (int i = 1; i <= r; ++i) 
    		{
    			for (int j = 1; j <= n; ++j) 
    			{
    				//if (l[j][b[i]] >= INF) continue;  //剪枝
    				for (int k = 1; k <= n; ++k) 
    				{
    					//if (d[i - 1][k] >= INF) continue;  //剪枝
    					if (j == k) 
    					{
    						if (l[b[i - 1]][b[i]] < INF) 
    						{
    							d[i][j] = min(d[i][j], d[i - 1][k] + l[b[i - 1]][b[i]]);
    						}
    					}
    					else 
    					{
    						//三个INF相加可能上溢
    						if (l[b[i - 1]][k] < INF && s[k][j] < INF && l[j][b[i]] < INF) 
    						{
    							d[i][j] = min(d[i][j], d[i - 1][k] + l[b[i - 1]][k] + s[k][j] + l[j][b[i]]);
    						}
    					}
    				}
    			}
    		}
    
    		int ans = INF;
    		for (int j = 1; j <= n; ++j) 
    		{
    			ans = min(ans, d[r][j]);
    		}
    		printf("%d
    ", ans);
    	}
    	return 0;
    }
  • 相关阅读:
    SuperMap房产测绘成果管理平台
    SuperMap产权登记管理平台
    Android adb shell am 的用法(1)
    由浅入深谈Perl中的排序
    Android 内存监测和分析工具
    Android 网络通信
    adb server is out of date. killing...
    引导页使用ViewPager遇到OutofMemoryError的解决方案
    adb logcat 详解
    How to send mail by java mail in Android uiautomator testing?
  • 原文地址:https://www.cnblogs.com/demian/p/7396472.html
Copyright © 2011-2022 走看看