D. Almost Acyclic Graph(拓扑)

原题: http://codeforces.com/problemset/problem/915/D

题意: 一个n<500,m<1e5的有向图,你可以删除其中一条边,问是否可能不存在环。

解析:

自己想就是怎么找到一条边使所有的环都经过这条边。答案一定在两个环的公共边中,然后各种问题各种解决……

到头来还是用了别人的方法,写这篇博客的时候心情压抑啊。(不得不承认方法是真的好)

先是方法: 因为边太多,不可能枚举每条边做一遍。但是点只有500,可以枚举每一个有入度的点,让这个点入度-1再跑。

这里还是自己证明一下正确性吧,安心一点……

证明:

就结果而言,每条边造成的结果只是让一个点的入度+1而已。

假设没有进行-1操作,有一个点,在拓扑排序后入度只剩1,说明我们可以删除其后面的那条边使之入度为0,那么这个点就会进入队列将所在环删除。

而枚举每个点使之入度-1,就相当于上面的将最后一条边删除。所以似乎可以通过记录删除的边号来得出:需要删除的哪条边。

#include<bits/stdc++.h>
using namespace std;

const int maxn=509,maxm=1e5+9;
int x[maxm],y[maxm];
int n,m;
vector<int>Ed[maxn];
bool vis[maxm];

int in[maxn];
int tmpin[maxn];
int cnt;
void topology(){
    queue<int>Q;
    cnt=0;
    for(int i=1;i<=n;i++){
        if(!tmpin[i])Q.push(i),cnt++;
    }
    while(!Q.empty()){
        int p=Q.front();Q.pop();
        for(int i=0;i<Ed[p].size();i++){
            int ed=Ed[p][i];
            vis[ed]=1;
            tmpin[y[ed]]--;
            if(tmpin[y[ed]]==0)Q.push(y[ed]),cnt++;
        }
    }
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",x+i,y+i);
        in[y[i]]++;
        Ed[x[i]].push_back(i);
    }
    for(int i=1;i<=n;i++){
        if(in[i]){
            memcpy(tmpin,in,sizeof(in));
            tmpin[i]--;
            topology();
            if(cnt==n){
                return 0*printf("YES\n");
            }
        }
    }
    printf("NO\n");
}



猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/88924111