Codeforces 915D Almost Acyclic Graph

题意翻译

给定一个n个顶点,m条边的有向图。你允许从其中去掉最多一条边。

你能够去掉最多一条边就让这个图无环吗?我们称一个有向图无环,当且仅当它不包含一个环(起点和终点相同的路径)。

输入格式:

第一行两个正整数n,mn,m 2\le n\le 500,1\le m\le min(n(n-1),100000)2≤n≤500,1≤m≤min(n(n?1),100000) ,代表图的顶点数和边数。

接下来mm 行,每行两个数u,vu,v ,表示有一条从uu 到vv 的有向边(1\le u,v\le n,u\ne v1≤u,v≤n,u≠v )。一对(u,v)(u,v) 最多出现一次。

输出格式:

如果有可能把这个图变成无环图,输出YES,否则输出NO。

说明:

第一个样例中,去掉2\to 32→3 的边即可。

第二个样例中,需要至少去掉两条边(例如2\to 12→1 和2\to 32→3 )才能让这个图变成无环图。

Translated by @小粉兔

题目描述

You are given a directed graph consisting of nn vertices and mm edges (each edge is directed, so it can be traversed in only one direction). You are allowed to remove at most one edge from it.

Can you make this graph acyclic by removing at most one edge from it? A directed graph is called acyclic iff it doesn‘t contain any cycle (a non-empty path that starts and ends in the same vertex).

输入输出格式

输入格式:

The first line contains two integers nn and mm ( 2<=n<=5002<=n<=500 , 1<=m<=min(n(n-1),100000)1<=m<=min(n(n?1),100000) ) — the number of vertices and the number of edges, respectively.

Then mm lines follow. Each line contains two integers uu and vv denoting a directed edge going from vertex uu to vertex vv( 1<=u,v<=n1<=u,v<=n , u≠vu≠v ). Each ordered pair (u,v)(u,v) is listed at most once (there is at most one directed edge from uu to vv ).

输出格式:

If it is possible to make this graph acyclic by removing at most one edge, print YES. Otherwise, print NO.

输入输出样例

输入样例#1:

3 4
1 2
2 3
3 2
3 1

输出样例#1:

YES

输入样例#2:

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

输出样例#2:

NO

说明

In the first example you can remove edge , and the graph becomes acyclic.

In the second example you have to remove at least two edges (for example,  and ) in order to make the graph acyclic.

果然样例都是骗人的www,疯狂WA并不知道我的dfs大法哪里错了。。。。

先贴一下WA代码,,,突然有点思路再去换一种方式怼怼

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define ll long long
#define maxn 505
#define maxm 100005
using namespace std;
int to[maxm],ne[maxm];
int hd[maxn],n,m,cnt[maxm];
int circle,st[maxn],tp;
int a[maxn][maxn];
bool v[maxn];

bool dfs(int x){
    v[x]=1;
    st[++tp]=x;

    bool can=1;
    for(int i=hd[x];i;i=ne[i]){
        if(!v[to[i]]){
            if(!dfs(to[i])){
                can=0;
                break;
            }
        }
        else{
            bool flag=0;
            circle++,cnt[i]++;
            if(cnt[i]==circle) flag=1;

            for(int j=tp;j>1;j--){
                if(st[j]==to[i]) break;
                if((++cnt[a[st[j-1]][st[j]]])==circle) flag=1;
            }

            if(!flag){
                can=0;
                break;
            }
        }
    }

    tp--;
    if(can) return 1;
    else return 0;
}

int main(){
    scanf("%d%d",&n,&m);
    int uu,vv;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&uu,&vv),a[uu][vv]=i;
        to[i]=vv,ne[i]=hd[uu],hd[uu]=i;
    }

    for(int i=1;i<=n;i++) if(!v[i]) if(!dfs(i)){
        puts("NO");
        return 0;
    }

    puts("YES");
    return 0;
}          

突然意识到了我这个算法的错误之处orz,虽然v[to[i]]为真的时候可能是找到了一个环,但是很可能此时栈中已经没有to[i]了(注意这是有向图啊,

可以先搜到to[i]然后发现扩展不出去了之后退回来),而且还有v[to[i]]为真的时候没有找到一个环呢,,,,

所以,,,,貌似不能dfs大法好了www

好了终于过了。。。。

首先讲一下为什么不能枚举边然后dfs。

为什么很多人觉得图的遍历的复杂度是O(N)?????

难道你不得把边都扫一遍吗???O(N+M)这是理论下界、、、

所以暴力枚举边+DFS是O(M^2+N*M)的,这就是某些人炸掉还不知道自己哪里错了的原因hhhh

记得学拓扑排序的时候是说过有环的图不能拓排的,但是暴力枚举边肯定还不行。

可以发现的是删一条边对拓扑排序的影响可以只有某个点的入度-1了,我们可以不用准确的知道这条边是哪条,

因为就算再图中不删这条边的话也顶多会让一个原本就能进队列的点最后的入度变成-1,这个是没有什么影响的(当然如果你写拓排入队列的判断

是id[x]<=0的话就当我没说。。。);但是还有一个我们想要的性质:如果这条边的终点原本进步了队列且终止入度为1的话,删这条边就恰好能让它

进来了。

这样做就可以了,复杂度O(N*N+N*M)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
#define ll long long
#define maxn 505
#define maxm 100005
using namespace std;
int to[maxm],ne[maxm];
int hd[maxn],n,m,tot;
int id[maxn],a[maxn];

inline bool solve(int x){
    memcpy(a,id,sizeof(id));
    a[x]--,tot=0;

    queue<int> q;
    for(int i=1;i<=n;i++) if(!a[i]) q.push(i),tot++;
    while(!q.empty()){
        x=q.front(),q.pop();
        for(int i=hd[x];i;i=ne[i]) if(!(--a[to[i]])){
            q.push(to[i]);
            tot++;
        }
    }

    return (tot==n);
}

int main(){
    int uu,vv;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&uu,&vv);
        id[vv]++,to[i]=vv,ne[i]=hd[uu],hd[uu]=i;
    }

    for(int i=1;i<=n;i++) if(solve(i)){
        puts("YES");
        return 0;
    }

    puts("NO");
    return 0;
}

原文地址:https://www.cnblogs.com/JYYHH/p/8401417.html

时间: 2024-10-02 01:50:31

Codeforces 915D Almost Acyclic Graph的相关文章

Almost Acyclic Graph CodeForces - 915D (思维+拓扑排序判环)

Almost Acyclic Graph CodeForces - 915D time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output You are given a directed graph consisting of n vertices and m edges (each edge is directed, so it can

【CodeForces】915 D. Almost Acyclic Graph 拓扑排序找环

[题目]D. Almost Acyclic Graph [题意]给定n个点的有向图(无重边),问能否删除一条边使得全图无环.n<=500,m<=10^5. [算法]拓扑排序 [题解]找到一个简单环,则欲删除的边一定经过该环.尝试环上的每一条边(至多n条边)后再次拓扑排序判断全图是否有环. 拓扑排序后定位到简单环:剩余图是环+环内DAG,DFS过程中将走入死路的点标-1,访问过标1,找到访问过的点就是简单环.换起始点直到找到环为止. 复杂度O(nm). #include<cstdio>

Codeforces 459E Pashmak and Graph(dp+贪心)

题目链接:Codeforces 459E Pashmak and Graph 题目大意:给定一张有向图,每条边有它的权值,要求选定一条路线,保证所经过的边权值严格递增,输出最长路径. 解题思路:将边按照权值排序,每次将相同权值的边同时加入,维护每个点作为终止点的最大长度即可. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 3

Almost Acyclic Graph Codeforces - 915D

以前做过的题都不会了.... 此题做法:优化的暴力 有一个显然的暴力:枚举每一条边试着删掉 注意到题目要求使得图无环,那么找出图上任意一个环,都应当要在其某一处断开(当然没有环是YES) 因此找出图中任意一个简单环(点不重复),枚举断开其上每一条边即可(共最多n条边) 复杂度O(n*(n+m)) 注意:不能用拓扑排序找出在任意环上的点再找任意环,因为拓扑排序后入度不为0的不一定是环上的点(比如可能是某个点,没有出边,仅有一条入边,是某个环上的点引出的)(曾经错了) 1 #include<cstd

codeforces 340D Bubble Sort Graph(dp,LIS)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud  Bubble Sort Graph Iahub recently has learned Bubble Sort, an algorithm that is used to sort a permutation with n elements a1, a2, ..., an in ascending order. He is bored of this so simple al

Codeforces 459E Pashmak and Graph

http://www.codeforces.com/problemset/problem/459/E 题意: 给出n个点,m条边的有向图,每个边有边权,求一条最长的边权上升的路径的长度. 思路:用f存边,g存点,然后排序转移,注意相同的要延迟转移 1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstring> 5 #include<iostream> 6

Codeforces 340D Bubble Sort Graph 规律+LIS

http://codeforces.com/problemset/problem/340/D 题意:给出一个n个数构成的排列,类似冒泡排序,若a[i]>a[i+1] a[i]-a[i+1]连边 并swap(a[i],a[i+1])反复操作 直到排序结束,n<=1e5,问该图构成的最大独立集大小为? 最大独立集:集合中任意两点无边相连. 直接建图显然不行,找规律:a[i]和后面比它大的都不会连边.a[i],x,y下标递增,冒泡排序,a[i]<x<y x和y不可能交换x>y 则x

Codeforces 715B. Complete The Graph 最短路,Dijkstra,构造

原文链接https://www.cnblogs.com/zhouzhendong/p/CF715B.html 题解 接下来说的“边”都指代“边权未知的边”. 将所有边都设为 L+1,如果dis(S,T) < L ,那么必然无解. 将所有边都设为 1 ,如果 dis(S,T) > L ,那么必然无解. 考虑将任意一条边的权值+1,则 dis(S,T) 会 +0 或者 +1 . 如果将所有边按照某一个顺序不断+1,直到所有边的权值都是L+1了,那么在这个过程中,dis(S,T) 是递增的,而且一定

Codeforces 716D - Complete The Graph(最短路)

题意:给定n个点,m条边,以及起点s,终点t,问你图中是否存在s->t的最短路为L,其中权值为0的可以任意修改. 思路:对给定的边分为2类,权重不为0的直接扔进去建图,权重为0的边先存起来.接着跑一遍堆优化的dij,如果dis[t]小于L,那么无论怎么修改权重0的边都没有办法凑出最短路L: 如果dis[t]=L,那么直接输出:如果dis[t]>L,则将原来事先存起来的边一条一条的加进去,权值设为1.每加一条边就跑一次dij,一旦找到dis[t]<=L,就可以终止并输出. PS:原来堆优化