zoukankan      html  css  js  c++  java
  • uva 1040(最小生成树+搜索)(World Final C题) Apare_xzc

    uva 1040 解题报告

    xzc 2019/3/27


    vjudge链接:The Traveling Judges Problem


    题意:

    CSDN上找的中文题面
    问题描述
    
      一组人要担任在一个特定城市举办的比赛的评委,他们需要找到最便宜的租车方式使得每个人都到达目标城市。他们观察发现,如果几个人在旅途的某一段坐同一辆租的车,就可以减少总费用。你的任务就是找出这些人应该采取的路线使得租车的总费用最小。
      我们假定:
      1. 租一辆车的费用与它行驶的距离成正比,没有燃油、保险、乘客人数多于一个等产生的额外费用。
      2. 所有车的费用与行驶距离的比例相同。
      3. 一辆车可以容纳任意数量的乘客。
      4. 任意一对城市之间最多只有一条道路直接相连,每条道路都是双向的且长度大于0。
      5. 每个人的起始城市到目标城市都至少有一种路线。
      6. 若多个人的路线中经过同一城市,则这些人从该城市到目标城市必乘同一辆车。
      7. 一个人可以乘一辆车到某个城市,再乘另一辆车离开该城市。
    
    输入格式
    
      第一行包含三个整数nc, dc和nr,表示地图上的城市个数,目标城市的编号和地图上的道路条数。
      接下来nr行每行包含三个整数c1, c2和dist,表示一条长度为dist的双向道路(c1, c2)。
      接下来一行包含一个整数nj,表示人数。
      接下来一行包含nj个整数,表示每个人的起始城市。
    
    输出格式
    
      第一行包含“distance = ”和一个整数,表示所租的车行驶的最小总距离。
      接下来nj行每行包含一个人的访问路线,城市按访问顺序给出并用“-”连接。
      存在多种方案时,选择需要访问到的城市集合元素最少的一种;仍然存在多种方案时,选择集合元素升序排列后字典序最小的一种。
      
    样例输入
    
    5 3 5
    1 2 1
    2 3 2
    3 4 3
    4 5 1
    2 4 2
    2
    5 1
    
    样例输出
    
    distance = 6
    5-4-2-3
    1-2-3
    
    样例输入
    
    4 4 3
    1 3 1
    2 3 2
    3 4 2
    2
    1 2
    
    样例输出
    
    distance = 5
    1-3-4
    2-3-4
    
    样例输入
    
    3 3 3
    1 2 2
    1 3 3
    2 3 1
    2
    2 1
    
    样例输出
    
    distance = 3
    2-3
    1-2-3
    --------------------- 
    作者:CSDN知名群众 
    来源:CSDN 
    原文:https://blog.csdn.net/weixin_42765557/article/details/87967603 
    版权声明:本文为博主原创文章,转载请附上博文链接!
    

    思路:

    • 思路大致是求最小生成树。
    • 但是答案有限制,就是在总距离最短的情况下,要求途径子节点的集合最小,如果集合最小(结点个数),那么要求集合排序后字典序最小
    • 我一开始直跑了一遍prim,但是Wa了,可能是字典序的问题。
    • 我后来dfs出子图的结点集合,然后以所有裁判那个共同的目的地为根结点,prim跑出这个子图的MST,然后判断是否可达每个裁判起点,若可达,更新答案。

    我的代码:

    /*
    #18948904 | XuZhichao's solution for [UVA-1040] [Problem B]
    Accepted
    3175  0ms
    C++11 5.3.0
    2019-03-27 16:52:53
    Shared
    */
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <vector>
    #define Mst(a,b) memset(a,(b),sizeof(a))
    #define For(i,a,b) for(register int i=(a);i<=(b);++i)
    #define LL long long
    using namespace std;
    const int maxn = 25;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    LL resDis,ans;
    int resNode;
    LL dis[50][50]; ///邻接矩阵存图
    LL D[maxn]; ///到生成树的距离
    int pre[maxn],ed;//ed为目的地 
    int ansPre[maxn];
    bool vis[maxn];
    bool isSt[maxn]; ///isSt[i]==true 表示第i个地方有人出发
    void getPath(int *,int);
    int s[25],totPerson;
    bool inSubgraph[maxn];
    bool prim(int ed,int n,int tot,int numOfNode); //数的根节点,节点总个数,起点的总数 
    void solve(int n)
    {
    	//For(i,1,n) cout<<s[i];cout<<endl;
    	int numOfNode = 0; //子图的节点数 
    	Mst(inSubgraph,0);
    	For(i,1,n) if(s[i]) ++numOfNode,inSubgraph[i] = true;
    	if(prim(ed,n,totPerson,numOfNode))
    	{
    		For(i,1,n) ansPre[i] = pre[i];
    		resDis = ans;
    	}
    }
    int numOf1;
    void dfs(int x,int n)
    {
    	if(x==n+1)
    	{
    		solve(n);
    		return;
    	}
    	s[x] = 1; 
    	dfs(x+1,n);
    	if(!isSt[x]&&x!=ed) s[x] = 0,dfs(x+1,n);
    }
    
    int main()
    {
    	//freopen("in.txt","r",stdin);
       	//freopen("out.txt","w",stdout);
        int n,nedge,nperson,u,v,ca=0; LL d;
        while(scanf("%d",&n)!=EOF&&n!=-1)
        {
        	//if(ca) printf("
    "); 
            printf("Case %d: distance = ",++ca);
            Mst(isSt,false);
            Mst(dis,0x3f);
            resDis = INF;
            scanf("%d%d",&ed,&nedge);
            For(i,1,nedge)
            {
                scanf("%d%d%lld",&u,&v,&d);
                dis[u][v] = d;
                dis[v][u] = d;
            }
            scanf("%d",&nperson);
            vector<int>person;
            For(i,1,nperson)
                scanf("%d",&u),person.push_back(u),isSt[u] = true;
        	totPerson = 0;
        	For(i,1,n) totPerson += isSt[i];  
        	dfs(1,n);
        	printf("%lld
    ",resDis);
        	for(auto &x:person)
        	{
        		getPath(ansPre,x);
    		}
    		printf("
    ");
        }
    	return 0;
    }
    void getPath(int * pre,int x)
    {
        printf("   %d",x);
        while(x!=ed)
        {
            x = pre[x];
            printf("-%d",x);
        }
        printf("
    ");
    }
    bool prim(int ed,int n,int tot,int numOfNode) //起点,n,必须到达的节点的总数,图中节点的总数, 
    {
        ans = 0;
        Mst(vis,0);
        For(i,1,n)
            D[i] = dis[ed][i], pre[i] = ed; //初始化 
        //D[ed] = 0;
        vis[ed] = true;
        int MinNode = -1;
        int numOfNodeInMST = 0; 
       	while(true) 
        {
            LL nowDis = INF;
            For(i,1,n)
            {
                if(vis[i]||!inSubgraph[i]) continue;//已经被访问或者不在这个子图中
                if(D[i]<nowDis)
                {
                    MinNode = i;
                    nowDis = D[i];
                }
            }
            if(MinNode==-1) break;
            ans += nowDis;
            vis[MinNode] = true;
            ++numOfNodeInMST;
            For(i,1,n)
            {
                if(vis[i]) continue;
                if(dis[MinNode][i]<D[i]||dis[MinNode][i]==D[i]&&MinNode<pre[i])
                {
                    D[i] = dis[MinNode][i];
                    pre[i] = MinNode;
                }
            }
            if(isSt[MinNode])
            {
                --tot;
                if(tot==0) 
    			{
    				break;
    			}
            }
        }
        if(tot) return false; //有的起点不可达 
        if(ans<resDis||ans==resDis&&numOfNodeInMST<resNode) return true;
        return false;
    }
    
  • 相关阅读:
    [翻译]Kafka Streams简介: 让流处理变得更简单
    KafkaClient接口与Kafka处理请求的若干特性
    KIP-32 Add timestamps to Kafka message
    (翻译)Google Guava Cache
    Kerberos的组件和术语(翻译和注解)
    目录
    java map 分析
    编译原理
    Java中的SPI(Service Provider Interface)
    新型数据库Kudu应用经验分享
  • 原文地址:https://www.cnblogs.com/Apare-xzc/p/12243662.html
Copyright © 2011-2022 走看看