zoukankan      html  css  js  c++  java
  • 题解 P4645 【[COCI2006-2007 Contest#3] BICIKLI】

    这个人怎么一天水四篇题解
    %%%chen_zhe女装大佬

    如果这题没有环的话只能算是一个简单dp题,然而有了环就会出现一些非常诡异并且棘手的情况。

    首先看一下这组数据,由可爱的机房友人提供。

    5 5
    1 4
    4 2
    3 5
    5 3
    3 4
    

    要画出来的话,大概是这个样子:

    卧槽这是什么垃圾东西

    总之就是,由1出发,4的入度-1,然而4的入度仍不为零,无法进行进一步的运算了。要说有环还的确是有环,不过这个环不仅没用还让我们的(dp_2)的值变成了0。

    这样的毒瘤东西绝对不能要啊,但是怎么样的点才是像这样没用的点呢?我们发现,环里面的点可以到达2,但是从1根本就进不去这个环啊。

    那么我们分别以1和2为起点进行一次正dfs和一次逆dfs标记能够从1能够到达的点和能够到达2的点。

    必须两个都能到达才是有用的点,否则就要把这个点删掉。

    然后删完就能快乐dp了。首先到达1的方法数肯定是1,然后对于每个没有前驱的点,将它的后继的方法数加上该点的方法数,删除该点和与该点相连的边。就是拓扑排序。

    参考代码和其他补充如下:

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,u,v,in[10005];
    long long dp[10005];
    bool mk[10005][2],flag;
    vector<int>dis[10005],des[10005];
    queue<int>que;
    void ring0(int p){
        mk[p][0]=1;
        for(int i=0;i<dis[p].size();i++)
            if(!mk[dis[p][i]][0])
                ring0(dis[p][i]);
    }//标记以1为起点能够达到的点
    void ring1(int p){
        mk[p][1]=1;
        for(int i=0;i<des[p].size();i++)
            if(!mk[des[p][i]][1])
                ring1(des[p][i]);
    }//标记能够达到2的点
    int main(){
        cin>>n>>m;
        for(int i=1;i<=m;i++){
            cin>>u>>v;
            dis[u].push_back(v);
            des[v].push_back(u);
            in[v]++;
        }
        dp[1]=1;
        ring0(1);
        ring1(2);
        for(int i=1;i<=n;i++)
            if(!mk[i][1]||!mk[i][0])
                for(int j=0;j<dis[i].size();j++)
                    in[dis[i][j]]--;//删除无用点
        for(int i=1;i<=n;i++)
            if(in[i]==0&&mk[i][0]&&mk[i][1])
                que.push(i);//拓扑排序初始化
        int top;
        while(!que.empty()){
            top=que.front();
            que.pop();
            for(int i=0;i<dis[top].size();i++){
                if(in[dis[top][i]]&&mk[dis[top][i]][0]&&mk[dis[top][i]][1]){
                    dp[dis[top][i]]+=dp[top];//dp刷表转移
                    dp[dis[top][i]]%=1000000000;
                    in[dis[top][i]]--;
                    if(in[dis[top][i]]==0)
                        que.push(dis[top][i]);//拓扑排序过程。
                }
            }
        }
        for(int i=1;i<=n;i++)
            if(in[i]&&mk[i][0]&&mk[i][1]){
                cout<<"inf";
                return 0;
            }//如果有用的点的入度还不为0,那么在1到2的路径上存在环,输出inf
        cout<<dp[2];
    }
    

    I'm Schwarzkopf Henkal.

  • 相关阅读:
    说实话,mycat就是垃圾,不再更新
    深入理解并发/并行,阻塞/非阻塞,同步/异步
    转载:PHP 协程实现
    转载:异步、并发、协程原理
    第四章总结
    第三节 需要异常
    [第四章] 测试依赖性和异常
    第三章总结
    第三节 MVC应用程序架构和测试
    第二节 PHPUnit测试的剖析
  • 原文地址:https://www.cnblogs.com/Schwarzkopf-Henkal/p/11775576.html
Copyright © 2011-2022 走看看