zoukankan      html  css  js  c++  java
  • POJ 3411 DFS

    大致题意:
    有n座城市和m(1<=n,m<=10)条路。现在要从城市1到城市n。有些路是要收费的,从a城市到b城市,如果之前到过c城市,那么只要付P的钱,如果没有去过就付R的钱。求的是最少要花多少钱。
    注意:路径是有向的。

    解题思路:
    DFS。这题当有了思路后,做起来是没有难度的,但是思维推算能力要求很高。

    这题难点在于“城市与城市之间可能存在多条路径”:
    1、 输入数据时可能会出现多条 从城市a到城市b的路径信息,但是费用有所差别;
    2、 对于 从城市a到城市b 的同一条路径,允许重复走。

    有人会问,重复走同一条路径有什么意义?单纯增加费用而已,为什么不能标记所有路径,每条路只允许走一次,这样费用不是更少么?
    我开始也是陷入了这种思维,但是这种想法其实“对一半,错一半”。
    先来看一组数据:
    6 5
    1 2 1 10 10
    2 3 4 10 100
    2 4 2 15 15
    4 1 1 12 12
    3 6 6 10 10
    如果每条路只允许走一次,那么方案只有1个:
    1à2à3à6 共135元
    但这组数据的正确答案是67元。为什么?正确的方案如下:
    1à2à4à1à2à3à6 共67元
    显然1à2重复走了一次,目的是为了先到达城市4,从而使得2à3这段路的费用从100缩减到10元。
    转载自:優YoU http://blog.csdn.net/lyy289065406/article/details/6689310

    因为就10个点,100条边。
    考虑DFS
    我们考虑有没有环路的时候不一定非要标记一个点被访问了多少次。
    (个人认为这样并不科学)
    小優YoU(这应该叫前辈了吧)说:
    那么应该重复多少次才合理?这与m值有关。题目的m值范围为<=10,那么当人一个城市被到达的次数若 >3次(不包括3),所走的方案必然出现了环路(网上的同学称之为“闸数”)。因此只需把bool vist[] 修改为 int vist[] 进行标记,本题就能解决了。

    但是并没有说出为什么一个点被访问3次就不能更优了,,
    所以我认为这是数据水,卡过去的。。

    我是把所有的vis设成m,每个点m次,,肯定所有的最优环都包括了。
    加个剪枝:if(cost>ans)return;
    也是0ms。。。。。

    // by SiriusRen
    #include <cstdio>
    using namespace std;
    int n,m,xx,yy,p,r,ans=0x3fffffff,vis[105],P[105],R[105];
    int first[15],next[105],v[105],C[105],VIS[105];
    void dfs(int x,int cost){
        VIS[x]++;
        if(cost>ans)return;
        if(x==n&&ans>cost)ans=cost;
        for(int i=first[x];i;i=next[i])
            if(VIS[v[i]]<=m){
                if(VIS[C[i]])dfs(v[i],cost+P[i]);
                else dfs(v[i],cost+R[i]);
                VIS[v[i]]--;
            }
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            scanf("%d%d%d%d%d",&p,&v[i],&C[i],&P[i],&R[i]);
            next[i]=first[p],first[p]=i;
        }
        VIS[1]=1,dfs(1,0);
        if(ans!=0x3fffffff)printf("%d
    ",ans);
        else puts("impossible");
    }

    但是还有几个版本莫名其妙AC,,,
    1.
    统计每个边经过的次数,次数小于等于2。

    0msAC

    // by SiriusRen
    #include <cstdio>
    using namespace std;
    int n,m,xx,yy,p,r,ans=0x3fffffff,vis[105],P[105],R[105];
    int first[15],next[105],v[105],C[105],VIS[105];
    void dfs(int x,int cost){
        if(x==n&&ans>cost)ans=cost;
        for(int i=first[x];i;i=next[i])
            if(vis[i]<=1){
                vis[i]++,VIS[v[i]]++;
                if(VIS[C[i]])dfs(v[i],cost+P[i]);
                else dfs(v[i],cost+R[i]);
                vis[i]--,VIS[v[i]]--;
            }
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            scanf("%d%d%d%d%d",&p,&v[i],&C[i],&P[i],&R[i]);
            next[i]=first[p],first[p]=i;
        }
        VIS[1]=1,dfs(1,0);
        if(ans!=0x3fffffff)printf("%d
    ",ans);
        else puts("impossible");
    }

    2.统计每个点经过的次数。
    次数小于等于3. 这里就不放代码了。。。 网上一抓一大把

    乱做实验的后果,,,
    这里写图片描述

  • 相关阅读:
    Runtime类
    递归(99乘法表)
    计算某天是在一年中的第几天
    数组逆序输出
    打印数组格式
    选择排序(直接把最小或最大的数选出来排列)
    冒泡排序
    比较两个字符数组是否相等
    汉字转阿斯克马值
    R语言调用C函数
  • 原文地址:https://www.cnblogs.com/SiriusRen/p/6532376.html
Copyright © 2011-2022 走看看