• 洛谷 p2196 挖地雷 题解


    好久没有写博客了,今天水几篇博客

    传送门

    挖地雷这个题之前在  信息学奥赛一本通  上做过几乎一样的题,但是由于数据太水导致我当时过了,进而导致我昨天(4.28)考试丢了20分,今天写一篇题解

    这个挖地雷我们首先要想一个问题(基本人人能想到):

    看这个图,如果我们从4出发,假设能挖到10颗雷,那么我们从1或3出发肯定能挖到更多的雷,毕竟你不可能挖到的雷是负数个或者会丢失雷

    那么我们就应该从没有入度的点开始,这貌似跟最短路差不多  

    思路:

    a:

    1.从入度为0的点开始,若能更新它的出边的点则更新,然后删边并让它的入度减一,若减到0则入队.

    2.标记刚刚更新的点

    3.检查是否全部标记

    if(全部标记)

      goto b;

    4.不断重复 goto a;

    注意:并不是只有更新过的点才删边及减入度,不管有无更新,与入度为0的点相连的边都要删,入度都要减(如果不明白可以拿上面那个图手动模拟一下就知道为什么了)

    b:

    交代

    .-' _..`.
    / .'_.'.'
    | .' (.)`.
    ;' ,_ `.
    .--.__________.' ; `.;-'
    | ./ /
    | | /
    `..'`-._ _____, ..'
    / | | | |
    / /| | | |
    / / | | | |
    /_/ |_| |_| \_
    |__ |__ |__ |__
    (这是一种神奇的生物自己可以手动增加空格把他复原)

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<cstdlib>
    #include<stack>
    #include<queue>
    #include<iostream>
    using namespace std;
    bool b[21][21];//临界矩阵存边
    stack <int> ss;//栈输出路径
    int a[21],du[21],s[21],pre[21];//a[]->每个地窖的地雷数,du[]指入度,s[]指当前挖到这个地窖最优,pre[]用来记录路径
    int n,yyy;//n指有几个地窖,yyy用来去掉最后的空格
    queue <int> q;//队列储存入度为0
    void print(int x) {//打印路径
        if(x==0)//没有前驱就返回
            return ;
        yyy++;
        ss.push(x);
        print(pre[x]);//递归找
    }
    void dd(int x) {
        for(int i=1; i<=n; i++) {//枚举每一个点
            if(b[x][i] == 1) {//有路的话
                b[x][i] = 0;//删边
                du[i]--;//减度
                if(du[i] == 0) {//如果减到0就入队
                    q.push(i);
                }(这几句不能放到下面)
                if(s[i] < s[x]+a[i]) {//如果能更新就更新
                    s[i] = s[x]+a[i];
                    pre[i] = x;//记录路径
                }
            }
    
        }
    
    }
    void dg() {
        for(int i=1; i<=n; i++) {//找一开始入度为0的边
            if(du[i] == 0) {
                q.push(i);
            }
        }
        while(q.empty() == 0) {//这个可以写到dd()里面
            int a=q.front();
            q.pop();
            dd(a);
        }
    }
    
    int main() {
    //    freopen("lei.in","r",stdin);
    //    freopen("lei.out","w",stdout);
        scanf("%d",&n);
        for(int i=1; i<=n; i++) {
            scanf("%d",&a[i]);
            s[i]= a[i];//一开始最优就是只走一个
        }
        for(int i=1; i<=n; i++) {
            for(int j=i+1; j<=n; j++) {
                scanf("%d",&b[i][j]);
                if(b[i][j] == 1)//记录度数
                    du[j]++;
            }
        }
    
        dg();
        int zd=0,xx;
        for(int i=1; i<=n; i++) {//找到最大值,并找到最大值的序号
            if(s[i]>zd) {
                zd=s[i];
                xx=i;
            }
        }
        print(xx);//打印
        for(int i=1; i<yyy; i++) {//yyy的用途
            cout<<ss.top()<<' ';
            ss.pop();
        }
        cout<<ss.top()<<endl;//最后换行格式错了貌似会WA
        cout<<zd;
        return 0;
    }

    一篇博客水完啦

  • 相关阅读:
    寒假了
    【MFC】浏览器中快速打开常用工具
    【转】MFC隐藏进程自身(任务管理器不可见,wSysCheck等工具可见)
    【原】DIY属于自己的鼠标侧键
    coco2dx 3.4final 使用scale9sprite
    linux挂载新硬盘
    关于c语言中的结构体使用偏移量求值问题
    Linux的网卡由eth0变成了eth1,如何修复
    oracle归档管理
    exsi上虚拟因硬盘不足无法启动
  • 原文地址:https://www.cnblogs.com/lztzs/p/10788358.html
Copyright © 2020-2023  润新知